Socket
Socket
Sign inDemoInstall

tailwindcss

Package Overview
Dependencies
Maintainers
3
Versions
1738
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

tailwindcss - npm Package Compare versions

Comparing version 0.0.0-insiders.6d04c2d to 0.0.0-insiders.6d9ae82

colors.d.ts

3

colors.js

@@ -1,1 +0,2 @@

module.exports = require('./lib/public/colors').default
let colors = require('./lib/public/colors')
module.exports = (colors.__esModule ? colors : { default: colors }).default

@@ -1,1 +0,2 @@

module.exports = require('./lib/public/default-config').default
let defaultConfig = require('./lib/public/default-config')
module.exports = (defaultConfig.__esModule ? defaultConfig : { default: defaultConfig }).default

@@ -1,1 +0,2 @@

module.exports = require('./lib/public/default-theme').default
let defaultTheme = require('./lib/public/default-theme')
module.exports = (defaultTheme.__esModule ? defaultTheme : { default: defaultTheme }).default

@@ -5,12 +5,33 @@ "use strict";

});
exports.lazyAutoprefixer = lazyAutoprefixer;
exports.lazyCssnano = lazyCssnano;
exports.postcss = void 0;
let postcss = require('postcss');
exports.postcss = postcss;
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
lazyPostcss: function() {
return lazyPostcss;
},
lazyPostcssImport: function() {
return lazyPostcssImport;
},
lazyAutoprefixer: function() {
return lazyAutoprefixer;
},
lazyCssnano: function() {
return lazyCssnano;
}
});
function lazyPostcss() {
return require("postcss");
}
function lazyPostcssImport() {
return require("postcss-import");
}
function lazyAutoprefixer() {
return require('autoprefixer');
return require("autoprefixer");
}
function lazyCssnano() {
return require('cssnano');
return require("cssnano");
}
#!/usr/bin/env node
"use strict";
var _indexJs = require("../peers/index.js");
var _chokidar = _interopRequireDefault(require("chokidar"));
var _path = _interopRequireDefault(require("path"));
var _arg = _interopRequireDefault(require("arg"));
var _fs = _interopRequireDefault(require("fs"));
var _postcssLoadConfig = _interopRequireDefault(require("postcss-load-config"));
var _cosmiconfig = require("cosmiconfig");
var _plugins // Little bit scary, looking at private/internal API
= _interopRequireDefault(require("postcss-load-config/src/plugins"));
var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures"));
var _resolveConfig = _interopRequireDefault(require("../resolveConfig"));
var _fastGlob = _interopRequireDefault(require("fast-glob"));
var _getModuleDependencies = _interopRequireDefault(require("./lib/getModuleDependencies"));
var _log = _interopRequireDefault(require("./util/log"));
var _packageJson = _interopRequireDefault(require("../package.json"));
var _normalizePath = _interopRequireDefault(require("normalize-path"));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let env = {
DEBUG: process.env.DEBUG !== undefined
};
// ---
function indentRecursive(node, indent = 0) {
node.each && node.each((child, i)=>{
if (!child.raws.before || !child.raws.before.trim() || child.raws.before.includes('\n')) {
child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}`;
}
child.raws.after = `\n${' '.repeat(indent)}`;
indentRecursive(child, indent + 1);
});
}
function formatNodes(root) {
indentRecursive(root);
if (root.first) {
root.first.raws.before = '';
}
}
function help({ message , usage , commands , options }) {
let indent = 2;
// Render header
console.log();
console.log(`${_packageJson.default.name} v${_packageJson.default.version}`);
// Render message
if (message) {
console.log();
for (let msg of message.split('\n')){
console.log(msg);
}
}
// Render usage
if (usage && usage.length > 0) {
console.log();
console.log('Usage:');
for (let example of usage){
console.log(' '.repeat(indent), example);
}
}
// Render commands
if (commands && commands.length > 0) {
console.log();
console.log('Commands:');
for (let command of commands){
console.log(' '.repeat(indent), command);
}
}
// Render options
if (options) {
let groupedOptions = {
};
for (let [key, value] of Object.entries(options)){
if (typeof value === 'object') {
groupedOptions[key] = {
...value,
flags: [
key
]
};
} else {
groupedOptions[value].flags.push(key);
}
}
console.log();
console.log('Options:');
for (let { flags , description , deprecated } of Object.values(groupedOptions)){
if (deprecated) continue;
if (flags.length === 1) {
console.log(' '.repeat(indent + 4 /* 4 = "-i, ".length */ ), flags.slice().reverse().join(', ').padEnd(20, ' '), description);
} else {
console.log(' '.repeat(indent), flags.slice().reverse().join(', ').padEnd(24, ' '), description);
}
}
}
console.log();
}
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 `tailwind.config.js` file'
},
'--postcss': {
type: Boolean,
description: 'Initialize a `postcss.config.js` 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'
},
'--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'
}
}
};
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.default.existsSync(_path.default.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 = (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') {
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();
// ---
function init() {
let messages = [];
var ref;
let tailwindConfigLocation = _path.default.resolve((ref = args['_'][1]) !== null && ref !== void 0 ? ref : './tailwind.config.js');
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');
// Change colors import
stubFile = stubFile.replace('../colors', 'tailwindcss/colors');
_fs.default.writeFileSync(tailwindConfigLocation, stubFile, 'utf8');
messages.push(`Created Tailwind CSS config file: ${_path.default.basename(tailwindConfigLocation)}`);
}
if (args['--postcss']) {
let postcssConfigLocation = _path.default.resolve('./postcss.config.js');
if (_fs.default.existsSync(postcssConfigLocation)) {
messages.push(`${_path.default.basename(postcssConfigLocation)} already exists.`);
} else {
let stubFile = _fs.default.readFileSync(_path.default.resolve(__dirname, '../stubs/defaultPostCssConfig.stub.js'), 'utf8');
_fs.default.writeFileSync(postcssConfigLocation, stubFile, 'utf8');
messages.push(`Created PostCSS config file: ${_path.default.basename(postcssConfigLocation)}`);
}
}
if (messages.length > 0) {
console.log();
for (let message of messages){
console.log(message);
}
}
}
async function build() {
let input = args['--input'];
let output = args['--output'];
let shouldWatch = args['--watch'];
let includePostCss = args['--postcss'];
// TODO: Deprecate this in future versions
if (!input && args['_'][1]) {
console.error('[deprecation] Running tailwindcss without -i, please provide an input file.');
input = args['--input'] = args['_'][1];
}
if (input && !_fs.default.existsSync(input = _path.default.resolve(input))) {
console.error(`Specified input file ${args['--input']} does not exist.`);
process.exit(9);
}
if (args['--config'] && !_fs.default.existsSync(args['--config'] = _path.default.resolve(args['--config']))) {
console.error(`Specified config file ${args['--config']} does not exist.`);
process.exit(9);
}
let configPath = args['--config'] ? args['--config'] : ((defaultPath)=>_fs.default.existsSync(defaultPath) ? defaultPath : null
)(_path.default.resolve('./tailwind.config.js'));
async function loadPostCssPlugins() {
let customPostCssPath = typeof args['--postcss'] === 'string' ? args['--postcss'] : undefined;
let { plugins: configPlugins } = customPostCssPath ? await (async ()=>{
let file = _path.default.resolve(customPostCssPath);
// Implementation, see: https://unpkg.com/browse/postcss-load-config@3.0.1/src/index.js
let { config ={
} } = await (0, _cosmiconfig).cosmiconfig('postcss').load(file);
if (typeof config === 'function') {
config = config();
} else {
config = Object.assign({
}, config);
}
if (!config.plugins) {
config.plugins = [];
}
return {
plugins: (0, _plugins).default(config, file)
};
})() : await (0, _postcssLoadConfig).default();
let configPluginTailwindIdx = configPlugins.findIndex((plugin)=>{
if (typeof plugin === 'function' && plugin.name === 'tailwindcss') {
return true;
}
if (typeof plugin === 'object' && plugin !== null && plugin.postcssPlugin === 'tailwindcss') {
return true;
}
return false;
});
let beforePlugins = configPluginTailwindIdx === -1 ? [] : configPlugins.slice(0, configPluginTailwindIdx);
let afterPlugins = configPluginTailwindIdx === -1 ? configPlugins : configPlugins.slice(configPluginTailwindIdx + 1);
return [
beforePlugins,
afterPlugins
];
}
function resolveConfig() {
let config = configPath ? require(configPath) : {
};
let resolvedConfig = (0, _resolveConfig).default(config);
if (args['--purge']) {
_log.default.warn('purge-flag-deprecated', [
'The `--purge` flag has been deprecated.',
'Please use `--content` instead.',
]);
if (!args['--content']) {
args['--content'] = args['--purge'];
}
}
if (args['--content']) {
resolvedConfig.content = args['--content'].split(/(?<!{[^}]+),/);
}
return resolvedConfig;
}
function extractFileGlobs(config) {
return config.content.files.filter((file)=>{
// Strings in this case are files / globs. If it is something else,
// like an object it's probably a raw content object. But this object
// is not watchable, so let's remove it.
return typeof file === 'string';
}).map((glob)=>(0, _normalizePath).default(glob)
);
}
function extractRawContent(config) {
return config.content.files.filter((file)=>{
return typeof file === 'object' && file !== null;
});
}
function getChangedContent(config) {
let changedContent = [];
// Resolve globs from the content config
let globs = extractFileGlobs(config);
let files = _fastGlob.default.sync(globs);
for (let file of files){
changedContent.push({
content: _fs.default.readFileSync(_path.default.resolve(file), 'utf8'),
extension: _path.default.extname(file).slice(1)
});
}
// Resolve raw content in the tailwind config
for (let { raw: content , extension ='html' } of extractRawContent(config)){
changedContent.push({
content,
extension
});
}
return changedContent;
}
async function buildOnce() {
let config = resolveConfig();
let changedContent = getChangedContent(config);
let tailwindPlugin = ()=>{
return {
postcssPlugin: 'tailwindcss',
Once (root, { result }) {
(0, _processTailwindFeatures).default(({ createContext })=>{
return ()=>{
return createContext(config, changedContent);
};
})(root, result);
}
};
};
tailwindPlugin.postcss = true;
let [beforePlugins, afterPlugins] = includePostCss ? await loadPostCssPlugins() : [
[],
[]
];
let plugins = [
...beforePlugins,
tailwindPlugin,
!args['--minify'] && formatNodes,
...afterPlugins,
!args['--no-autoprefixer'] && (()=>{
// Try to load a local `autoprefixer` version first
try {
return require('autoprefixer');
} catch {
}
return (0, _indexJs).lazyAutoprefixer();
})(),
args['--minify'] && (()=>{
let options = {
preset: [
'default',
{
cssDeclarationSorter: false
}
]
};
// Try to load a local `cssnano` version first
try {
return require('cssnano');
} catch {
}
return (0, _indexJs).lazyCssnano()(options);
})(),
].filter(Boolean);
let processor = (0, _indexJs).postcss(plugins);
function processCSS(css) {
let start = process.hrtime.bigint();
return Promise.resolve().then(()=>output ? _fs.default.promises.mkdir(_path.default.dirname(output), {
recursive: true
}) : null
).then(()=>processor.process(css, {
from: input,
to: output
})
).then((result)=>{
if (!output) {
return process.stdout.write(result.css);
}
return Promise.all([
_fs.default.promises.writeFile(output, result.css, ()=>true
),
result.map && _fs.default.writeFile(output + '.map', result.map.toString(), ()=>true
),
].filter(Boolean));
}).then(()=>{
let end = process.hrtime.bigint();
console.error();
console.error('Done in', (end - start) / BigInt(1000000) + 'ms.');
});
}
let css = input ? _fs.default.readFileSync(_path.default.resolve(input), 'utf8') : '@tailwind base; @tailwind components; @tailwind utilities';
return processCSS(css);
}
let context = null;
async function startWatcher() {
let changedContent = [];
let configDependencies = [];
let contextDependencies = new Set();
let watcher = null;
function refreshConfig() {
env.DEBUG && console.time('Module dependencies');
for (let file of configDependencies){
delete require.cache[require.resolve(file)];
}
if (configPath) {
configDependencies = (0, _getModuleDependencies).default(configPath).map(({ file })=>file
);
for (let dependency of configDependencies){
contextDependencies.add(dependency);
}
}
env.DEBUG && console.timeEnd('Module dependencies');
return resolveConfig();
}
let [beforePlugins, afterPlugins] = includePostCss ? await loadPostCssPlugins() : [
[],
[]
];
let plugins = [
...beforePlugins,
'__TAILWIND_PLUGIN_POSITION__',
!args['--minify'] && formatNodes,
...afterPlugins,
!args['--no-autoprefixer'] && (()=>{
// Try to load a local `autoprefixer` version first
try {
return require('autoprefixer');
} catch {
}
return (0, _indexJs).lazyAutoprefixer();
})(),
args['--minify'] && (()=>{
let options = {
preset: [
'default',
{
cssDeclarationSorter: false
}
]
};
// Try to load a local `cssnano` version first
try {
return require('cssnano');
} catch {
}
return (0, _indexJs).lazyCssnano()(options);
})(),
].filter(Boolean);
async function rebuild(config) {
env.DEBUG && console.time('Finished in');
let tailwindPlugin = ()=>{
return {
postcssPlugin: 'tailwindcss',
Once (root, { result }) {
env.DEBUG && console.time('Compiling CSS');
(0, _processTailwindFeatures).default(({ createContext })=>{
console.error();
console.error('Rebuilding...');
return ()=>{
if (context !== null) {
context.changedContent = changedContent.splice(0);
return context;
}
env.DEBUG && console.time('Creating context');
context = createContext(config, changedContent.splice(0));
env.DEBUG && console.timeEnd('Creating context');
return context;
};
})(root, result);
env.DEBUG && console.timeEnd('Compiling CSS');
}
};
};
tailwindPlugin.postcss = true;
let tailwindPluginIdx = plugins.indexOf('__TAILWIND_PLUGIN_POSITION__');
let copy = plugins.slice();
copy.splice(tailwindPluginIdx, 1, tailwindPlugin);
let processor = (0, _indexJs).postcss(copy);
function processCSS(css) {
let start = process.hrtime.bigint();
return Promise.resolve().then(()=>output ? _fs.default.promises.mkdir(_path.default.dirname(output), {
recursive: true
}) : null
).then(()=>processor.process(css, {
from: input,
to: output
})
).then(async (result)=>{
for (let message of result.messages){
if (message.type === 'dependency') {
contextDependencies.add(message.file);
}
}
watcher.add([
...contextDependencies
]);
if (!output) {
return process.stdout.write(result.css);
}
await Promise.all([
_fs.default.promises.writeFile(output, result.css, ()=>true
),
result.map && _fs.default.writeFile(output + '.map', result.map.toString(), ()=>true
),
].filter(Boolean));
}).then(()=>{
let end = process.hrtime.bigint();
console.error('Done in', (end - start) / BigInt(1000000) + 'ms.');
}).catch((err)=>{
if (err.name === 'CssSyntaxError') {
console.error(err.toString());
} else {
console.error(err);
}
});
}
let css = input ? _fs.default.readFileSync(_path.default.resolve(input), 'utf8') : '@tailwind base; @tailwind components; @tailwind utilities';
let result1 = await processCSS(css);
env.DEBUG && console.timeEnd('Finished in');
return result1;
}
let config = refreshConfig(configPath);
if (input) {
contextDependencies.add(_path.default.resolve(input));
}
watcher = _chokidar.default.watch([
...contextDependencies,
...extractFileGlobs(config)
], {
ignoreInitial: true
});
let chain = Promise.resolve();
watcher.on('change', async (file)=>{
if (contextDependencies.has(file)) {
env.DEBUG && console.time('Resolve config');
context = null;
config = refreshConfig(configPath);
env.DEBUG && console.timeEnd('Resolve config');
env.DEBUG && console.time('Watch new files');
let globs = extractFileGlobs(config);
watcher.add(configDependencies);
watcher.add(globs);
env.DEBUG && console.timeEnd('Watch new files');
chain = chain.then(async ()=>{
changedContent.push(...getChangedContent(config));
await rebuild(config);
});
} else {
chain = chain.then(async ()=>{
changedContent.push({
content: _fs.default.readFileSync(_path.default.resolve(file), 'utf8'),
extension: _path.default.extname(file).slice(1)
});
await rebuild(config);
});
}
});
watcher.on('add', async (file)=>{
chain = chain.then(async ()=>{
changedContent.push({
content: _fs.default.readFileSync(_path.default.resolve(file), 'utf8'),
extension: _path.default.extname(file).slice(1)
});
await rebuild(config);
});
});
chain = chain.then(()=>{
changedContent.push(...getChangedContent(config));
return rebuild(config);
});
}
if (shouldWatch) {
/* Abort the watcher if stdin is closed to avoid zombie processes */ process.stdin.on('end', ()=>process.exit(0)
);
process.stdin.resume();
startWatcher();
} else {
buildOnce();
}
}
module.exports = require("./cli/index");

@@ -5,4 +5,9 @@ "use strict";

});
exports.default = void 0;
var _default = [
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _default = [
"preflight",

@@ -28,4 +33,6 @@ "container",

"boxSizing",
"lineClamp",
"display",
"aspectRatio",
"size",
"height",

@@ -42,3 +49,5 @@ "maxHeight",

"tableLayout",
"captionSide",
"borderCollapse",
"borderSpacing",
"transformOrigin",

@@ -62,2 +71,3 @@ "translate",

"listStyleType",
"listStyleImage",
"appearance",

@@ -94,3 +104,5 @@ "columns",

"textOverflow",
"hyphens",
"whitespace",
"textWrap",
"wordBreak",

@@ -133,2 +145,6 @@ "borderRadius",

"textDecoration",
"textDecorationColor",
"textDecorationStyle",
"textDecorationThickness",
"textUnderlineOffset",
"fontSmoothing",

@@ -143,3 +159,7 @@ "placeholderColor",

"boxShadow",
"outline",
"boxShadowColor",
"outlineStyle",
"outlineWidth",
"outlineOffset",
"outlineColor",
"ringWidth",

@@ -175,4 +195,5 @@ "ringColor",

"willChange",
"content"
"contain",
"content",
"forcedColorAdjust"
];
exports.default = _default;

@@ -5,8 +5,22 @@ "use strict";

});
exports.flagEnabled = flagEnabled;
exports.issueFlagNotices = issueFlagNotices;
exports.default = void 0;
var _chalk = _interopRequireDefault(require("chalk"));
var _log = _interopRequireDefault(require("./util/log"));
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
flagEnabled: function() {
return flagEnabled;
},
issueFlagNotices: function() {
return issueFlagNotices;
},
default: function() {
return _default;
}
});
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 : {

@@ -17,8 +31,17 @@ default: obj

let defaults = {
optimizeUniversalDefaults: true
optimizeUniversalDefaults: false,
generalizedModifiers: true,
disableColorOpacityUtilitiesByDefault: false,
relativeContentPathsByDefault: false
};
let featureFlags = {
future: [],
future: [
"hoverOnlyWhenSupported",
"respectDefaultRingColorOpacity",
"disableColorOpacityUtilitiesByDefault",
"relativeContentPathsByDefault"
],
experimental: [
'optimizeUniversalDefaults'
"optimizeUniversalDefaults",
"generalizedModifiers"
]

@@ -28,10 +51,10 @@ };

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 ref;
var ref11, ref12;
return config.experimental === 'all' || ((ref12 = (ref11 = config === null || config === void 0 ? void 0 : (ref = config.experimental) === null || ref === void 0 ? void 0 : ref[flag]) !== null && ref11 !== void 0 ? ref11 : defaults[flag]) !== null && ref12 !== void 0 ? ref12 : 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);
}

@@ -41,9 +64,7 @@ return false;

function experimentalFlagsEnabled(config) {
if (config.experimental === 'all') {
if (config.experimental === "all") {
return featureFlags.experimental;
}
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]);
}

@@ -55,11 +76,9 @@ function issueFlagNotices(config) {

if (experimentalFlagsEnabled(config).length > 0) {
let changes = experimentalFlagsEnabled(config).map((s)=>_chalk.default.yellow(s)
).join(', ');
_log.default.warn('experimental-flags-enabled', [
let changes = experimentalFlagsEnabled(config).map((s)=>_picocolors.default.yellow(s)).join(", ");
_log.default.warn("experimental-flags-enabled", [
`You have enabled experimental features: ${changes}`,
'Experimental features in Tailwind CSS are not covered by semver, may introduce breaking changes, and can change at any time.',
"Experimental features in Tailwind CSS are not covered by semver, may introduce breaking changes, and can change at any time."
]);
}
}
var _default = featureFlags;
exports.default = _default;
const _default = featureFlags;
"use strict";
var _setupTrackingContext = _interopRequireDefault(require("./lib/setupTrackingContext"));
var _setupWatchingContext = _interopRequireDefault(require("./lib/setupWatchingContext"));
var _processTailwindFeatures = _interopRequireDefault(require("./processTailwindFeatures"));
var _sharedState = require("./lib/sharedState");
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) {
let setupContext = _sharedState.env.TAILWIND_MODE === 'watch' ? (0, _setupWatchingContext).default(configOrPath) : (0, _setupTrackingContext).default(configOrPath);
(0, _processTailwindFeatures).default(setupContext)(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");

@@ -5,10 +5,15 @@ "use strict";

});
exports.default = collapseAdjacentRules;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return collapseAdjacentRules;
}
});
let comparisonMap = {
atrule: [
'name',
'params'
"name",
"params"
],
rule: [
'selector'
"selector"
]

@@ -18,3 +23,3 @@ };

function collapseAdjacentRules() {
return (root)=>{
function collapseRulesIn(root) {
let currentRule = null;

@@ -31,8 +36,10 @@ root.each((node)=>{

let properties = comparisonMap[node.type];
var _property, _property1;
if (node.type === 'atrule' && node.name === 'font-face') {
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, ' ')
)) {
currentRule.append(node.nodes);
} 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)
if (node.nodes) {
currentRule.append(node.nodes);
}
node.remove();

@@ -43,3 +50,16 @@ } else {

});
// After we've collapsed adjacent rules & at-rules, we need to collapse
// adjacent rules & at-rules that are children of at-rules.
// We do not care about nesting rules because Tailwind CSS
// explicitly does not handle rule nesting on its own as
// the user is expected to use a nesting plugin
root.each((node)=>{
if (node.type === "atrule") {
collapseRulesIn(node);
}
});
}
return (root)=>{
collapseRulesIn(root);
};
}

@@ -5,10 +5,19 @@ "use strict";

});
exports.default = _default;
var _dlv = _interopRequireDefault(require("dlv"));
var _didyoumean = _interopRequireDefault(require("didyoumean"));
var _transformThemeValue = _interopRequireDefault(require("../util/transformThemeValue"));
var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
var _buildMediaQuery = _interopRequireDefault(require("../util/buildMediaQuery"));
var _toPath = require("../util/toPath");
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
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__*/ _interop_require_default(require("../util/buildMediaQuery"));
const _toPath = require("../util/toPath");
const _withAlphaVariable = require("../util/withAlphaVariable");
const _pluginUtils = require("../util/pluginUtils");
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -19,22 +28,21 @@ default: obj

function isObject(input) {
return typeof input === 'object' && input !== null;
return typeof input === "object" && input !== null;
}
function findClosestExistingPath(theme, path) {
let parts = (0, _toPath).toPath(path);
let parts = (0, _toPath.toPath)(path);
do {
parts.pop();
if ((0, _dlv).default(theme, parts) !== undefined) break;
}while (parts.length)
if ((0, _dlv.default)(theme, parts) !== undefined) break;
}while (parts.length);
return parts.length ? parts : undefined;
}
function pathToString(path) {
if (typeof path === 'string') return path;
if (typeof path === "string") return path;
return path.reduce((acc, cur, i)=>{
if (cur.includes('.')) return `${acc}[${cur}]`;
if (cur.includes(".")) return `${acc}[${cur}]`;
return i === 0 ? cur : `${acc}.${cur}`;
}, '');
}, "");
}
function list(items) {
return items.map((key)=>`'${key}'`
).join(', ');
return items.map((key)=>`'${key}'`).join(", ");
}

@@ -44,10 +52,10 @@ function listKeys(obj) {

}
function validatePath(config, path, defaultValue) {
const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+/g, '').replace(/['"]+$/g, '');
const pathSegments = Array.isArray(path) ? path : (0, _toPath).toPath(pathString);
const value = (0, _dlv).default(config.theme, pathString, defaultValue);
function validatePath(config, path, defaultValue, themeOpts = {}) {
const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+|['"]+$/g, "");
const pathSegments = Array.isArray(path) ? path : (0, _toPath.toPath)(pathString);
const value = (0, _dlv.default)(config.theme, pathSegments, defaultValue);
if (value === undefined) {
let error = `'${pathString}' does not exist in your theme config.`;
const parentSegments = pathSegments.slice(0, -1);
const parentValue = (0, _dlv).default(config.theme, parentSegments);
const parentValue = (0, _dlv.default)(config.theme, parentSegments);
if (isObject(parentValue)) {

@@ -57,5 +65,4 @@ const validKeys = Object.keys(parentValue).filter((key)=>validatePath(config, [

key
]).isValid
);
const suggestion = (0, _didyoumean).default(pathSegments[pathSegments.length - 1], validKeys);
]).isValid);
const suggestion = (0, _didyoumean.default)(pathSegments[pathSegments.length - 1], validKeys);
if (suggestion) {

@@ -72,3 +79,3 @@ error += ` Did you mean '${pathToString([

if (closestPath) {
const closestValue = (0, _dlv).default(config.theme, closestPath);
const closestValue = (0, _dlv.default)(config.theme, closestPath);
if (isObject(closestValue)) {

@@ -88,3 +95,3 @@ error += ` '${pathToString(closestPath)}' has the following keys: ${listKeys(closestValue)}`;

}
if (!(typeof value === 'string' || typeof value === 'number' || typeof value === 'function' || value instanceof String || value instanceof Number || Array.isArray(value))) {
if (!(typeof value === "string" || typeof value === "number" || typeof value === "function" || value instanceof String || value instanceof Number || Array.isArray(value))) {
let error = `'${pathString}' was found but does not resolve to a string.`;

@@ -95,4 +102,3 @@ if (isObject(value)) {

key
]).isValid
);
]).isValid);
if (validKeys.length) {

@@ -113,16 +119,15 @@ error += ` Did you mean something like '${pathToString([

isValid: true,
value: (0, _transformThemeValue).default(themeSection)(value)
value: (0, _transformThemeValue.default)(themeSection)(value, themeOpts)
};
}
function extractArgs(node, vNodes, functions) {
vNodes = vNodes.map((vNode)=>resolveVNode(node, vNode, functions)
);
vNodes = vNodes.map((vNode)=>resolveVNode(node, vNode, functions));
let args = [
''
""
];
for (let vNode of vNodes){
if (vNode.type === 'div' && vNode.value === ',') {
args.push('');
if (vNode.type === "div" && vNode.value === ",") {
args.push("");
} else {
args[args.length - 1] += _postcssValueParser.default.stringify(vNode);
args[args.length - 1] += _index.default.stringify(vNode);
}

@@ -133,5 +138,5 @@ }

function resolveVNode(node, vNode, functions) {
if (vNode.type === 'function' && functions[vNode.value] !== undefined) {
if (vNode.type === "function" && functions[vNode.value] !== undefined) {
let args = extractArgs(node, vNode.nodes, functions);
vNode.type = 'word';
vNode.type = "word";
vNode.value = functions[vNode.value](node, ...args);

@@ -142,3 +147,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);

@@ -148,20 +155,84 @@ }).toString();

let nodeTypePropertyMap = {
atrule: 'params',
decl: 'value'
atrule: "params",
decl: "value"
};
function _default({ tailwindConfig: config }) {
/**
* @param {string} path
* @returns {Iterable<[path: string, alpha: string|undefined]>}
*/ function* toPaths(path) {
// Strip quotes from beginning and end of string
// This allows the alpha value to be present inside of quotes
path = path.replace(/^['"]+|['"]+$/g, "");
let matches = path.match(/^([^\s]+)(?![^\[]*\])(?:\s*\/\s*([^\/\s]+))$/);
let alpha = undefined;
yield [
path,
undefined
];
if (matches) {
path = matches[1];
alpha = matches[2];
yield [
path,
alpha
];
}
}
/**
*
* @param {any} config
* @param {string} path
* @param {any} defaultValue
*/ function resolvePath(config, path, defaultValue) {
const results = Array.from(toPaths(path)).map(([path, alpha])=>{
return Object.assign(validatePath(config, path, defaultValue, {
opacityValue: alpha
}), {
resolvedPath: path,
alpha
});
});
var _results_find;
return (_results_find = results.find((result)=>result.isValid)) !== null && _results_find !== void 0 ? _results_find : results[0];
}
function _default(context) {
let config = context.tailwindConfig;
let functions = {
theme: (node, path, ...defaultValue)=>{
const { isValid , value , error } = validatePath(config, path, defaultValue.length ? defaultValue : undefined);
let { isValid , value , error , alpha } = resolvePath(config, path, defaultValue.length ? defaultValue : undefined);
if (!isValid) {
var _parentNode_raws_tailwind;
let parentNode = node.parent;
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) {
// Remove this utility from any caches
context.markInvalidUtilityNode(parentNode);
// Remove the CSS node from the markup
parentNode.remove();
// Show a warning
_log.default.warn("invalid-theme-key-in-class", [
`The utility \`${candidate}\` contains an invalid theme value and was not generated.`
]);
return;
}
throw node.error(error);
}
let maybeColor = (0, _pluginUtils.parseColorFormat)(value);
let isColorFunction = maybeColor !== undefined && typeof maybeColor === "function";
if (alpha !== undefined || isColorFunction) {
if (alpha === undefined) {
alpha = 1.0;
}
value = (0, _withAlphaVariable.withAlphaValue)(maybeColor, alpha, maybeColor);
}
return value;
},
screen: (node, screen)=>{
screen = screen.replace(/^['"]+/g, '').replace(/['"]+$/g, '');
if (config.theme.screens[screen] === undefined) {
screen = screen.replace(/^['"]+/g, "").replace(/['"]+$/g, "");
let screens = (0, _normalizeScreens.normalizeScreens)(config.theme.screens);
let screenDefinition = screens.find(({ name })=>name === screen);
if (!screenDefinition) {
throw node.error(`The '${screen}' screen does not exist in your theme.`);
}
return (0, _buildMediaQuery).default(config.theme.screens[screen]);
return (0, _buildMediaQuery.default)(screenDefinition);
}

@@ -168,0 +239,0 @@ };

@@ -5,8 +5,15 @@ "use strict";

});
exports.default = expandApplyAtRules;
var _postcss = _interopRequireDefault(require("postcss"));
var _generateRules = require("./generateRules");
var _bigSign = _interopRequireDefault(require("../util/bigSign"));
var _escapeClassName = _interopRequireDefault(require("../util/escapeClassName"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return expandApplyAtRules;
}
});
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__*/ _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 : {

@@ -16,7 +23,152 @@ default: obj

}
/** @typedef {Map<string, [any, import('postcss').Rule[]]>} ApplyCache */ function extractClasses(node) {
/** @type {Map<string, Set<string>>} */ let groups = new Map();
let container = _postcss.default.root({
nodes: [
node.clone()
]
});
container.walkRules((rule)=>{
(0, _postcssselectorparser.default)((selectors)=>{
selectors.walkClasses((classSelector)=>{
let parentSelector = classSelector.parent.toString();
let classes = groups.get(parentSelector);
if (!classes) {
groups.set(parentSelector, classes = new Set());
}
classes.add(classSelector.value);
});
}).processSync(rule.selector);
});
let normalizedGroups = Array.from(groups.values(), (classes)=>Array.from(classes));
let classes = normalizedGroups.flat();
return Object.assign(classes, {
groups: normalizedGroups
});
}
let selectorExtractor = (0, _postcssselectorparser.default)();
/**
* @param {string} ruleSelectors
*/ function extractSelectors(ruleSelectors) {
return selectorExtractor.astSync(ruleSelectors);
}
function extractBaseCandidates(candidates, separator) {
let baseClasses = new Set();
for (let candidate of candidates){
baseClasses.add(candidate.split(separator).pop());
}
return Array.from(baseClasses);
}
function prefix(context, selector) {
let prefix = context.tailwindConfig.prefix;
return typeof prefix === 'function' ? prefix(selector) : prefix + selector;
return typeof prefix === "function" ? prefix(selector) : prefix + selector;
}
function buildApplyCache(applyCandidates, context) {
function* pathToRoot(node) {
yield node;
while(node.parent){
yield node.parent;
node = node.parent;
}
}
/**
* Only clone the node itself and not its children
*
* @param {*} node
* @param {*} overrides
* @returns
*/ function shallowClone(node, overrides = {}) {
let children = node.nodes;
node.nodes = [];
let tmp = node.clone(overrides);
node.nodes = children;
return tmp;
}
/**
* Clone just the nodes all the way to the top that are required to represent
* this singular rule in the tree.
*
* For example, if we have CSS like this:
* ```css
* @media (min-width: 768px) {
* @supports (display: grid) {
* .foo {
* display: grid;
* grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
* }
* }
*
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
*
* .baz {
* color: orange;
* }
* }
* ```
*
* And we're cloning `.bar` it'll return a cloned version of what's required for just that single node:
*
* ```css
* @media (min-width: 768px) {
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
* }
* ```
*
* @param {import('postcss').Node} node
*/ function nestedClone(node) {
for (let parent of pathToRoot(node)){
if (node === parent) {
continue;
}
if (parent.type === "root") {
break;
}
node = shallowClone(parent, {
nodes: [
node
]
});
}
return node;
}
/**
* @param {import('postcss').Root} root
*/ function buildLocalApplyCache(root, context) {
/** @type {ApplyCache} */ let cache = new Map();
root.walkRules((rule)=>{
// Ignore rules generated by Tailwind
for (let node of pathToRoot(rule)){
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;
}
}
// Clone what's required to represent this singular rule in the tree
let container = nestedClone(rule);
let sort = context.offsets.create("user");
for (let className of extractClasses(rule)){
let list = cache.get(className) || [];
cache.set(className, list);
list.push([
{
layer: "user",
sort,
important: false
},
container
]);
}
});
return cache;
}
/**
* @returns {ApplyCache}
*/ function buildApplyCache(applyCandidates, context) {
for (let candidate of applyCandidates){

@@ -30,7 +182,6 @@ if (context.notClassCache.has(candidate) || context.applyClassCache.has(candidate)) {

rule.clone()
]
));
]));
continue;
}
let matches = Array.from((0, _generateRules).resolveMatches(candidate, context));
let matches = Array.from((0, _generateRules.resolveMatches)(candidate, context));
if (matches.length === 0) {

@@ -44,5 +195,35 @@ context.notClassCache.add(candidate);

}
/**
* Build a cache only when it's first used
*
* @param {() => ApplyCache} buildCacheFn
* @returns {ApplyCache}
*/ function lazyCache(buildCacheFn) {
let cache = null;
return {
get: (name)=>{
cache = cache || buildCacheFn();
return cache.get(name);
},
has: (name)=>{
cache = cache || buildCacheFn();
return cache.has(name);
}
};
}
/**
* Take a series of multiple caches and merge
* them so they act like one large cache
*
* @param {ApplyCache[]} caches
* @returns {ApplyCache}
*/ function combineCaches(caches) {
return {
get: (name)=>caches.flatMap((cache)=>cache.get(name) || []),
has: (name)=>caches.some((cache)=>cache.has(name))
};
}
function extractApplyCandidates(params) {
let candidates = params.split(/[\s\t\n]+/g);
if (candidates[candidates.length - 1] === '!important') {
if (candidates[candidates.length - 1] === "!important") {
return [

@@ -58,46 +239,7 @@ candidates.slice(0, -1),

}
function partitionApplyParents(root) {
let applyParents = new Set();
root.walkAtRules('apply', (rule)=>{
applyParents.add(rule.parent);
});
for (let rule of applyParents){
let nodeGroups = [];
let lastGroup = [];
for (let node of rule.nodes){
if (node.type === 'atrule' && node.name === 'apply') {
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup);
lastGroup = [];
}
nodeGroups.push([
node
]);
} else {
lastGroup.push(node);
}
}
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup);
}
if (nodeGroups.length === 1) {
continue;
}
for (let group of [
...nodeGroups
].reverse()){
let newParent = rule.clone({
nodes: []
});
newParent.append(group);
rule.after(newParent);
}
rule.remove();
}
}
function processApply(root, context) {
function processApply(root, context, localCache) {
let applyCandidates = new Set();
// Collect all @apply rules and candidates
let applies = [];
root.walkAtRules('apply', (rule)=>{
root.walkAtRules("apply", (rule)=>{
let [candidates] = extractApplyCandidates(rule.params);

@@ -110,125 +252,308 @@ for (let util of candidates){

// Start the @apply process if we have rules with @apply in them
if (applies.length > 0) {
// Fill up some caches!
let applyClassCache = buildApplyCache(applyCandidates, context);
/**
* When we have an apply like this:
*
* .abc {
* @apply hover:font-bold;
* }
*
* What we essentially will do is resolve to this:
*
* .abc {
* @apply .hover\:font-bold:hover {
* font-weight: 500;
* }
* }
*
* Notice that the to-be-applied class is `.hover\:font-bold:hover` and that the utility candidate was `hover:font-bold`.
* What happens in this function is that we prepend a `.` and escape the candidate.
* This will result in `.hover\:font-bold`
* Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
*/ // TODO: Should we use postcss-selector-parser for this instead?
function replaceSelector(selector, utilitySelectors, candidate) {
let needle = `.${(0, _escapeClassName).default(candidate)}`;
let utilitySelectorsList = utilitySelectors.split(/\s*,\s*/g);
return selector.split(/\s*,\s*/g).map((s)=>{
let replaced = [];
for (let utilitySelector of utilitySelectorsList){
let replacedSelector = utilitySelector.replace(needle, s);
if (replacedSelector === utilitySelector) {
continue;
if (applies.length === 0) {
return;
}
// Fill up some caches!
let applyClassCache = combineCaches([
localCache,
buildApplyCache(applyCandidates, context)
]);
/**
* When we have an apply like this:
*
* .abc {
* @apply hover:font-bold;
* }
*
* What we essentially will do is resolve to this:
*
* .abc {
* @apply .hover\:font-bold:hover {
* font-weight: 500;
* }
* }
*
* Notice that the to-be-applied class is `.hover\:font-bold:hover` and that the utility candidate was `hover:font-bold`.
* What happens in this function is that we prepend a `.` and escape the candidate.
* This will result in `.hover\:font-bold`
* Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
*
* @param {string} selector
* @param {string} utilitySelectors
* @param {string} candidate
*/ function replaceSelector(selector, utilitySelectors, candidate) {
let selectorList = extractSelectors(selector);
let utilitySelectorsList = extractSelectors(utilitySelectors);
let candidateList = extractSelectors(`.${(0, _escapeClassName.default)(candidate)}`);
let candidateClass = candidateList.nodes[0].nodes[0];
selectorList.each((sel)=>{
/** @type {Set<import('postcss-selector-parser').Selector>} */ let replaced = new Set();
utilitySelectorsList.each((utilitySelector)=>{
let hasReplaced = false;
utilitySelector = utilitySelector.clone();
utilitySelector.walkClasses((node)=>{
if (node.value !== candidateClass.value) {
return;
}
replaced.push(replacedSelector);
// Don't replace multiple instances of the same class
// This is theoretically correct but only partially
// We'd need to generate every possible permutation of the replacement
// For example with `.foo + .foo { … }` and `section { @apply foo; }`
// We'd need to generate all of these:
// - `.foo + .foo`
// - `.foo + section`
// - `section + .foo`
// - `section + section`
if (hasReplaced) {
return;
}
// Since you can only `@apply` class names this is sufficient
// We want to replace the matched class name with the selector the user is using
// Ex: Replace `.text-blue-500` with `.foo.bar:is(.something-cool)`
node.replaceWith(...sel.nodes.map((node)=>node.clone()));
// Record that we did something and we want to use this new selector
replaced.add(utilitySelector);
hasReplaced = true;
});
});
// Sort tag names before class names (but only sort each group (separated by a combinator)
// separately and not in total)
// This happens when replacing `.bar` in `.foo.bar` with a tag like `section`
for (let sel of replaced){
let groups = [
[]
];
for (let node of sel.nodes){
if (node.type === "combinator") {
groups.push(node);
groups.push([]);
} else {
let last = groups[groups.length - 1];
last.push(node);
}
}
return replaced.join(', ');
}).join(', ');
}
let perParentApplies = new Map();
// Collect all apply candidates and their rules
for (let apply of applies){
let candidates = perParentApplies.get(apply.parent) || [];
perParentApplies.set(apply.parent, candidates);
let [applyCandidates, important] = extractApplyCandidates(apply.params);
if (apply.parent.type === 'atrule') {
if (apply.parent.name === 'screen') {
const screenType = apply.parent.params;
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.`);
sel.nodes = [];
for (let group of groups){
if (Array.isArray(group)) {
group.sort((a, b)=>{
if (a.type === "tag" && b.type === "class") {
return -1;
} else if (a.type === "class" && b.type === "tag") {
return 1;
} else if (a.type === "class" && b.type === "pseudo" && b.value.startsWith("::")) {
return -1;
} else if (a.type === "pseudo" && a.value.startsWith("::") && b.type === "class") {
return 1;
}
return 0;
});
}
sel.nodes = sel.nodes.concat(group);
}
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 applyCandidates){
if (!applyClassCache.has(applyCandidate)) {
if (applyCandidate === prefix(context, 'group')) {
// TODO: Link to specific documentation page with error code.
throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`);
}
throw apply.error(`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`);
sel.replaceWith(...replaced);
});
return selectorList.toString();
}
let perParentApplies = new Map();
// Collect all apply candidates and their rules
for (let apply of applies){
let [candidates] = perParentApplies.get(apply.parent) || [
[],
apply.source
];
perParentApplies.set(apply.parent, [
candidates,
apply.source
]);
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 ${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 applyCandidates){
if ([
prefix(context, "group"),
prefix(context, "peer")
].includes(applyCandidate)) {
// TODO: Link to specific documentation page with error code.
throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`);
}
if (!applyClassCache.has(applyCandidate)) {
throw apply.error(`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`);
}
let rules = applyClassCache.get(applyCandidate);
// Verify that we can apply the class
for (let [, rule] of rules){
if (rule.type === "atrule") {
continue;
}
let rules = applyClassCache.get(applyCandidate);
candidates.push([
applyCandidate,
important,
rules
]);
rule.walkRules(()=>{
throw apply.error([
`The \`${applyCandidate}\` class cannot be used with \`@apply\` because \`@apply\` does not currently support nested CSS.`,
"Rewrite the selector without nesting or configure the `tailwindcss/nesting` plugin:",
"https://tailwindcss.com/docs/using-with-preprocessors#nesting"
].join("\n"));
});
}
candidates.push([
applyCandidate,
important,
rules
]);
}
for (const [parent, candidates] of perParentApplies){
let siblings = [];
for (let [applyCandidate, important, rules] of candidates){
for (let [meta, node] of rules){
let root = _postcss.default.root({
nodes: [
node.clone()
]
}
for (let [parent, [candidates, atApplySource]] of perParentApplies){
let siblings = [];
for (let [applyCandidate, important, rules] of candidates){
let potentialApplyCandidates = [
applyCandidate,
...extractBaseCandidates([
applyCandidate
], context.tailwindConfig.separator)
];
for (let [meta, node] of rules){
let parentClasses = extractClasses(parent);
let nodeClasses = extractClasses(node);
// When we encounter a rule like `.dark .a, .b { … }` we only want to be left with `[.dark, .a]` if the base applyCandidate is `.a` or with `[.b]` if the base applyCandidate is `.b`
// So we've split them into groups
nodeClasses = nodeClasses.groups.filter((classList)=>classList.some((className)=>potentialApplyCandidates.includes(className))).flat();
// Add base utility classes from the @apply node to the list of
// classes to check whether it intersects and therefore results in a
// circular dependency or not.
//
// E.g.:
// .foo {
// @apply hover:a; // This applies "a" but with a modifier
// }
//
// We only have to do that with base classes of the `node`, not of the `parent`
// E.g.:
// .hover\:foo {
// @apply bar;
// }
// .bar {
// @apply foo;
// }
//
// This should not result in a circular dependency because we are
// just applying `.foo` and the rule above is `.hover\:foo` which is
// unrelated. However, if we were to apply `hover:foo` then we _did_
// have to include this one.
nodeClasses = nodeClasses.concat(extractBaseCandidates(nodeClasses, context.tailwindConfig.separator));
let intersects = parentClasses.some((selector)=>nodeClasses.includes(selector));
if (intersects) {
throw node.error(`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`);
}
let root = _postcss.default.root({
nodes: [
node.clone()
]
});
// Make sure every node in the entire tree points back at the @apply rule that generated it
root.walk((node)=>{
node.source = atApplySource;
});
let canRewriteSelector = node.type !== "atrule" || node.type === "atrule" && node.name !== "keyframes";
if (canRewriteSelector) {
root.walkRules((rule)=>{
// Let's imagine you have the following structure:
//
// .foo {
// @apply bar;
// }
//
// @supports (a: b) {
// .bar {
// color: blue
// }
//
// .something-unrelated {}
// }
//
// In this case we want to apply `.bar` but it happens to be in
// an atrule node. We clone that node instead of the nested one
// because we still want that @supports rule to be there once we
// applied everything.
//
// However it happens to be that the `.something-unrelated` is
// also in that same shared @supports atrule. This is not good,
// and this should not be there. The good part is that this is
// a clone already and it can be safely removed. The question is
// how do we know we can remove it. Basically what we can do is
// match it against the applyCandidate that you want to apply. If
// it doesn't match the we can safely delete it.
//
// If we didn't do this, then the `replaceSelector` function
// would have replaced this with something that didn't exist and
// therefore it removed the selector altogether. In this specific
// case it would result in `{}` instead of `.something-unrelated {}`
if (!extractClasses(rule).some((candidate)=>candidate === applyCandidate)) {
rule.remove();
return;
}
// Strip the important selector from the parent selector if at the beginning
let importantSelector = typeof context.tailwindConfig.important === "string" ? context.tailwindConfig.important : null;
// We only want to move the "important" selector if this is a Tailwind-generated utility
// We do *not* want to do this for user CSS that happens to be structured the same
let isGenerated = parent.raws.tailwind !== undefined;
let parentSelector = isGenerated && importantSelector && parent.selector.indexOf(importantSelector) === 0 ? parent.selector.slice(importantSelector.length) : parent.selector;
// 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 = (0, _applyImportantSelector.applyImportantSelector)(rule.selector, importantSelector);
}
rule.walkDecls((d)=>{
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();
});
let canRewriteSelector = node.type !== 'atrule' || node.type === 'atrule' && node.name !== 'keyframes';
if (canRewriteSelector) {
root.walkRules((rule)=>{
rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate);
rule.walkDecls((d)=>{
d.important = meta.important || important;
});
});
}
// Insert it
siblings.push([
// Ensure that when we are sorting, that we take the layer order into account
{
...meta,
sort: meta.sort | context.layerOrder[meta.layer]
},
root.nodes[0],
]);
}
// It could be that the node we were inserted was removed because the class didn't match
// If that was the *only* rule in the parent, then we have nothing add so we skip it
if (!root.nodes[0]) {
continue;
}
// Insert it
siblings.push([
meta.sort,
root.nodes[0]
]);
}
// Inject the rules, sorted, correctly
let nodes = siblings.sort(([a], [z])=>(0, _bigSign).default(a.sort - z.sort)
).map((s)=>s[1]
);
// console.log(parent)
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
parent.after(nodes);
}
for (let apply1 of applies){
// If there are left-over declarations, just remove the @apply
if (apply1.parent.nodes.length > 1) {
apply1.remove();
} else {
// The node is empty, drop the full node
apply1.parent.remove();
}
// Inject the rules, sorted, correctly
let nodes = context.offsets.sort(siblings).map((s)=>s[1]);
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
parent.after(nodes);
}
for (let apply of applies){
// If there are left-over declarations, just remove the @apply
if (apply.parent.nodes.length > 1) {
apply.remove();
} else {
// The node is empty, drop the full node
apply.parent.remove();
}
// Do it again, in case we have other `@apply` rules
processApply(root, context);
}
// Do it again, in case we have other `@apply` rules
processApply(root, context, localCache);
}
function expandApplyAtRules(context) {
return (root)=>{
partitionApplyParents(root);
processApply(root, context);
// Build a cache of the user's CSS so we can use it to resolve classes used by @apply
let localCache = lazyCache(()=>buildLocalApplyCache(root, context));
processApply(root, context, localCache);
};
}

@@ -5,9 +5,16 @@ "use strict";

});
exports.default = expandTailwindAtRules;
var _quickLru = _interopRequireDefault(require("quick-lru"));
var sharedState = _interopRequireWildcard(require("./sharedState"));
var _generateRules = require("./generateRules");
var _bigSign = _interopRequireDefault(require("../util/bigSign"));
var _cloneNodes = _interopRequireDefault(require("../util/cloneNodes"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return expandTailwindAtRules;
}
});
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__*/ _interop_require_default(require("../util/log"));
const _cloneNodes = /*#__PURE__*/ _interop_require_default(require("../util/cloneNodes"));
const _defaultExtractor = require("./defaultExtractor");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -17,56 +24,52 @@ default: obj

}
function _interopRequireWildcard(obj) {
if (obj && obj.__esModule) {
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
} else {
var newObj = {
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
if (obj != null) {
for(var key in obj){
if (Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {
};
if (desc.get || desc.set) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
newObj.default = obj;
return newObj;
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
let env = sharedState.env;
const PATTERNS = [
/([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source,
/([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source,
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source,
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source,
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source,
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source,
/([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source,
/([^<>"'`\s]*[^"'`\s:])/.source
].join('|');
const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g');
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g;
let env = _sharedState.env;
const builtInExtractors = {
DEFAULT: (content)=>{
let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [];
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [];
return [
...broadMatches,
...innerMatches
];
}
DEFAULT: _defaultExtractor.defaultExtractor
};
const builtInTransformers = {
DEFAULT: (content)=>content
,
svelte: (content)=>content.replace(/(?:^|\s)class:/g, ' ')
DEFAULT: (content)=>content,
svelte: (content)=>content.replace(/(?:^|\s)class:/g, " ")
};
function getExtractor(tailwindConfig, fileExtension) {
let extractors = tailwindConfig.content.extract;
return extractors[fileExtension] || extractors.DEFAULT || builtInExtractors[fileExtension] || builtInExtractors.DEFAULT;
function getExtractor(context, fileExtension) {
let extractors = context.tailwindConfig.content.extract;
return extractors[fileExtension] || extractors.DEFAULT || builtInExtractors[fileExtension] || builtInExtractors.DEFAULT(context);
}

@@ -83,7 +86,7 @@ function getTransformer(tailwindConfig, fileExtension) {

if (!extractorCache.has(extractor)) {
extractorCache.set(extractor, new _quickLru.default({
extractorCache.set(extractor, new _quicklru.default({
maxSize: 25000
}));
}
for (let line of content.split('\n')){
for (let line of content.split("\n")){
line = line.trim();

@@ -99,4 +102,3 @@ if (seen.has(line)) {

} else {
let extractorMatches = extractor(line).filter((s)=>s !== '!*'
);
let extractorMatches = extractor(line).filter((s)=>s !== "!*");
let lineMatchesSet = new Set(extractorMatches);

@@ -110,41 +112,17 @@ for (let match of lineMatchesSet){

}
function buildStylesheet(rules, context) {
let sortedRules = rules.sort(([a], [z])=>(0, _bigSign).default(a - z)
);
/**
*
* @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
* @param {*} context
*/ function buildStylesheet(rules, context) {
let sortedRules = context.offsets.sort(rules);
let returnValue = {
base: new Set(),
defaults: new Set(),
components: new Set(),
utilities: new Set(),
variants: new Set(),
// All the CSS that is not Tailwind related can be put in this bucket. This
// will make it easier to later use this information when we want to
// `@apply` for example. The main reason we do this here is because we
// still need to make sure the order is correct. Last but not least, we
// will make sure to always re-inject this section into the css, even if
// certain rules were not used. This means that it will look like a no-op
// from the user's perspective, but we gathered all the useful information
// we need.
user: new Set()
variants: new Set()
};
for (let [sort, rule] of sortedRules){
if (sort >= context.minimumScreen) {
returnValue.variants.add(rule);
continue;
}
if (sort & context.layerOrder.base) {
returnValue.base.add(rule);
continue;
}
if (sort & context.layerOrder.components) {
returnValue.components.add(rule);
continue;
}
if (sort & context.layerOrder.utilities) {
returnValue.utilities.add(rule);
continue;
}
if (sort & context.layerOrder.user) {
returnValue.user.add(rule);
continue;
}
returnValue[sort.layer].add(rule);
}

@@ -154,3 +132,3 @@ return returnValue;

function expandTailwindAtRules(context) {
return (root)=>{
return async (root)=>{
let layerNodes = {

@@ -162,39 +140,64 @@ base: null,

};
// Make sure this file contains Tailwind directives. If not, we can save
// a lot of work and bail early. Also we don't have to register our touch
// file as a dependency since the output of this CSS does not depend on
// the source of any templates. Think Vue <style> blocks for example.
root.walkAtRules('tailwind', (rule)=>{
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule;
root.walkAtRules((rule)=>{
// Make sure this file contains Tailwind directives. If not, we can save
// a lot of work and bail early. Also we don't have to register our touch
// file as a dependency since the output of this CSS does not depend on
// the source of any templates. Think Vue <style> blocks for example.
if (rule.name === "tailwind") {
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule;
}
}
});
if (Object.values(layerNodes).every((n)=>n === null
)) {
if (Object.values(layerNodes).every((n)=>n === null)) {
return root;
}
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
]);
let seen = new Set();
env.DEBUG && console.time('Reading changed files');
for (let { content , extension } of context.changedContent){
let transformer = getTransformer(context.tailwindConfig, extension);
let extractor = getExtractor(context.tailwindConfig, extension);
getClassCandidates(transformer(content), extractor, candidates, seen);
env.DEBUG && console.time("Reading changed files");
/** @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);
}));
}
env.DEBUG && console.timeEnd("Reading changed files");
// ---
// Generate the actual CSS
let classCacheCount = context.classCache.size;
env.DEBUG && console.time('Generate rules');
let rules = (0, _generateRules).generateRules(candidates, context);
env.DEBUG && console.timeEnd('Generate rules');
env.DEBUG && console.time("Generate rules");
env.DEBUG && console.time("Sorting candidates");
let sortedCandidates = 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");
// We only ever add to the classCache, so if it didn't grow, there is nothing new.
env.DEBUG && console.time('Build stylesheet');
env.DEBUG && console.time("Build stylesheet");
if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
for (let rule of rules){
context.ruleCache.add(rule);
}
context.stylesheetCache = buildStylesheet([

@@ -204,38 +207,71 @@ ...context.ruleCache

}
env.DEBUG && console.timeEnd('Build stylesheet');
let { base: baseNodes , components: componentNodes , utilities: utilityNodes , variants: screenNodes , } = context.stylesheetCache;
env.DEBUG && console.timeEnd("Build stylesheet");
let { defaults: defaultNodes , base: baseNodes , components: componentNodes , utilities: utilityNodes , variants: screenNodes } = context.stylesheetCache;
// ---
// Replace any Tailwind directives with generated CSS
if (layerNodes.base) {
layerNodes.base.before((0, _cloneNodes).default([
...baseNodes
], layerNodes.base.source));
layerNodes.base.before((0, _cloneNodes.default)([
...baseNodes,
...defaultNodes
], layerNodes.base.source, {
layer: "base"
}));
layerNodes.base.remove();
}
if (layerNodes.components) {
layerNodes.components.before((0, _cloneNodes).default([
layerNodes.components.before((0, _cloneNodes.default)([
...componentNodes
], layerNodes.components.source));
], layerNodes.components.source, {
layer: "components"
}));
layerNodes.components.remove();
}
if (layerNodes.utilities) {
layerNodes.utilities.before((0, _cloneNodes).default([
layerNodes.utilities.before((0, _cloneNodes.default)([
...utilityNodes
], layerNodes.utilities.source));
], layerNodes.utilities.source, {
layer: "utilities"
}));
layerNodes.utilities.remove();
}
// We do post-filtering to not alter the emitted order of the variants
const variantNodes = Array.from(screenNodes).filter((node)=>{
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") {
return layerNodes.components !== null;
}
if (parentLayer === "utilities") {
return layerNodes.utilities !== null;
}
return true;
});
if (layerNodes.variants) {
layerNodes.variants.before((0, _cloneNodes).default([
...screenNodes
], layerNodes.variants.source));
layerNodes.variants.before((0, _cloneNodes.default)(variantNodes, layerNodes.variants.source, {
layer: "variants"
}));
layerNodes.variants.remove();
} else {
root.append((0, _cloneNodes).default([
...screenNodes
], root.source));
} else if (variantNodes.length > 0) {
root.append((0, _cloneNodes.default)(variantNodes, root.source, {
layer: "variants"
}));
}
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 _node_raws_tailwind;
return ((_node_raws_tailwind = node.raws.tailwind) === null || _node_raws_tailwind === void 0 ? void 0 : _node_raws_tailwind.parentLayer) === "utilities";
});
if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
_log.default.warn("content-problems", [
"No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.",
"https://tailwindcss.com/docs/content-configuration"
]);
}
// ---
if (env.DEBUG) {
console.log('Potential classes: ', candidates.size);
console.log('Active contexts: ', sharedState.contextSourcesMap.size);
console.log("Potential classes: ", candidates.size);
console.log("Active contexts: ", _sharedState.contextSourcesMap.size);
}

@@ -245,3 +281,3 @@ // Clear the cache for the changed files

// Cleanup any leftover @layer atrules
root.walkAtRules('layer', (rule)=>{
root.walkAtRules("layer", (rule)=>{
if (Object.keys(layerNodes).includes(rule.params)) {

@@ -248,0 +284,0 @@ rule.remove();

@@ -5,11 +5,36 @@ "use strict";

});
exports.generateRules = exports.resolveMatches = void 0;
var _postcss = _interopRequireDefault(require("postcss"));
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
var _parseObjectStyles = _interopRequireDefault(require("../util/parseObjectStyles"));
var _isPlainObject = _interopRequireDefault(require("../util/isPlainObject"));
var _prefixSelector = _interopRequireDefault(require("../util/prefixSelector"));
var _pluginUtils = require("../util/pluginUtils");
var _log = _interopRequireDefault(require("../util/log"));
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
getClassNameFromSelector: function() {
return getClassNameFromSelector;
},
resolveMatches: function() {
return resolveMatches;
},
generateRules: function() {
return generateRules;
}
});
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__*/ _interop_require_default(require("../util/log"));
const _sharedState = /*#__PURE__*/ _interop_require_wildcard(require("./sharedState"));
const _formatVariantSelector = require("../util/formatVariantSelector");
const _nameClass = require("../util/nameClass");
const _dataTypes = require("../util/dataTypes");
const _setupContextUtils = require("./setupContextUtils");
const _isSyntacticallyValidPropertyValue = /*#__PURE__*/ _interop_require_default(require("../util/isSyntacticallyValidPropertyValue"));
const _splitAtTopLevelOnly = require("../util/splitAtTopLevelOnly.js");
const _featureFlags = require("../featureFlags");
const _applyImportantSelector = require("../util/applyImportantSelector");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -19,5 +44,43 @@ default: obj

}
let classNameParser = (0, _postcssSelectorParser).default((selectors)=>{
return selectors.first.filter(({ type })=>type === 'class'
).pop().value;
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
let classNameParser = (0, _postcssselectorparser.default)((selectors)=>{
return selectors.first.filter(({ type })=>type === "class").pop().value;
});

@@ -34,31 +97,43 @@ function getClassNameFromSelector(selector) {

// ['grid', 'cols-[[linename],1fr,auto]']
function* candidatePermutations(candidate, lastIndex = Infinity) {
if (lastIndex < 0) {
return;
function* candidatePermutations(candidate) {
let lastIndex = Infinity;
while(lastIndex >= 0){
let dashIdx;
let wasSlash = false;
if (lastIndex === Infinity && candidate.endsWith("]")) {
let bracketIdx = candidate.indexOf("[");
// If character before `[` isn't a dash or a slash, this isn't a dynamic class
// eg. string[]
if (candidate[bracketIdx - 1] === "-") {
dashIdx = bracketIdx - 1;
} else if (candidate[bracketIdx - 1] === "/") {
dashIdx = bracketIdx - 1;
wasSlash = true;
} else {
dashIdx = -1;
}
} else if (lastIndex === Infinity && candidate.includes("/")) {
dashIdx = candidate.lastIndexOf("/");
wasSlash = true;
} else {
dashIdx = candidate.lastIndexOf("-", lastIndex);
}
if (dashIdx < 0) {
break;
}
let prefix = candidate.slice(0, dashIdx);
let modifier = candidate.slice(wasSlash ? dashIdx : dashIdx + 1);
lastIndex = dashIdx - 1;
// TODO: This feels a bit hacky
if (prefix === "" || modifier === "/") {
continue;
}
yield [
prefix,
modifier
];
}
let dashIdx;
if (lastIndex === Infinity && candidate.endsWith(']')) {
let bracketIdx = candidate.indexOf('[');
// If character before `[` isn't a dash or a slash, this isn't a dynamic class
// eg. string[]
dashIdx = [
'-',
'/'
].includes(candidate[bracketIdx - 1]) ? bracketIdx - 1 : -1;
} else {
dashIdx = candidate.lastIndexOf('-', lastIndex);
}
if (dashIdx < 0) {
return;
}
let prefix = candidate.slice(0, dashIdx);
let modifier = candidate.slice(dashIdx + 1);
yield [
prefix,
modifier
];
yield* candidatePermutations(candidate, dashIdx - 1);
}
function applyPrefix(matches, context) {
if (matches.length === 0 || context.tailwindConfig.prefix === '') {
if (matches.length === 0 || context.tailwindConfig.prefix === "") {
return matches;

@@ -74,4 +149,10 @@ }

});
let classCandidate = match[1].raws.tailwind.classCandidate;
container.walkRules((r)=>{
r.selector = (0, _prefixSelector).default(context.tailwindConfig.prefix, r.selector);
// If this is a negative utility with a dash *before* the prefix we
// have to ensure that the generated selector matches the candidate
// Not doing this will cause `-tw-top-1` to generate the class `.tw--top-1`
// The disconnect between candidate <-> class can cause @apply to hard crash.
let shouldPrependNegative = classCandidate.startsWith("-");
r.selector = (0, _prefixSelector.default)(context.tailwindConfig.prefix, r.selector, shouldPrependNegative);
});

@@ -83,3 +164,3 @@ match[1] = container.nodes[0];

}
function applyImportant(matches) {
function applyImportant(matches, classCandidate) {
if (matches.length === 0) {

@@ -89,2 +170,5 @@ return matches;

let result = [];
function isInKeyframes(rule) {
return rule.parent && rule.parent.type === "atrule" && rule.parent.name === "keyframes";
}
for (let [meta, rule] of matches){

@@ -97,7 +181,14 @@ let container = _postcss.default.root({

container.walkRules((r)=>{
r.selector = (0, _pluginUtils).updateAllClasses(r.selector, (className)=>{
return `!${className}`;
});
r.walkDecls((d)=>d.important = true
);
// Declarations inside keyframes cannot be marked as important
// They will be ignored by the browser
if (isInKeyframes(r)) {
return;
}
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);
});

@@ -126,6 +217,78 @@ result.push([

}
/** @type {{modifier: string | null, value: string | null}} */ let args = {
modifier: null,
value: _sharedState.NONE
};
// Retrieve "modifier"
{
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")) {
return [];
}
}
}
// Retrieve "arbitrary value"
if (variant.endsWith("]") && !variant.startsWith("[")) {
// We either have:
// @[200px]
// group-[:hover]
//
// But we don't want:
// @-[200px] (`-` is incorrect)
// group[:hover] (`-` is missing)
let match = /(.)(-?)\[(.*)\]/g.exec(variant);
if (match) {
let [, char, separator, value] = match;
// @-[200px] case
if (char === "@" && separator === "-") return [];
// group[:hover] case
if (char !== "@" && separator === "") return [];
variant = variant.replace(`${separator}[${value}]`, "");
args.value = value;
}
}
// Register arbitrary variants
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) {
let sort = context.offsets.recordVariant(variant);
let selector = (0, _dataTypes.normalize)(variant.slice(1, -1));
let selectors = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(selector, ",");
// We do not support multiple selectors for arbitrary variants
if (selectors.length > 1) {
return [];
}
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)) {
let variantFunctionTuples = context.variantMap.get(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){
// Don't generate variants for user css
if (meta.layer === "user") {
continue;
}
let container = _postcss.default.root({

@@ -136,7 +299,17 @@ nodes: [

});
for (let [variantSort, variantFunction] of variantFunctionTuples){
let clone = container.clone();
for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples){
let clone = (containerFromArray !== null && containerFromArray !== void 0 ? containerFromArray : container).clone();
let collectedFormats = [];
function prepareBackup() {
// Already prepared, chicken out
if (clone.raws.neededBackup) {
return;
}
clone.raws.neededBackup = true;
clone.walkRules((rule)=>rule.raws.originalSelector = rule.selector);
}
function modifySelectors(modifierFunction) {
prepareBackup();
clone.each((rule)=>{
if (rule.type !== 'rule') {
if (rule.type !== "rule") {
return;

@@ -156,13 +329,103 @@ }

let ruleWithVariant = variantFunction({
container: clone,
// Public API
get container () {
prepareBackup();
return clone;
},
separator: context.tailwindConfig.separator,
modifySelectors
modifySelectors,
// Private API for now
wrap (wrapper) {
let nodes = clone.nodes;
clone.removeAll();
wrapper.append(nodes);
clone.append(wrapper);
},
format (selectorFormat) {
collectedFormats.push({
format: selectorFormat,
respectPrefix
});
},
args
});
// It can happen that a list of format strings is returned from within the function. In that
// case, we have to process them as well. We can use the existing `variantSort`.
if (Array.isArray(ruleWithVariant)) {
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
// currently looping over. However, you can also think of it like a processing queue
// where you keep handling jobs until everything is done and each job can queue more
// jobs if needed.
variantFunctionTuples.push([
context.offsets.applyParallelOffset(variantSort, idx),
variantFunction,
// If the clone has been modified we have to pass that back
// though so each rule can use the modified container
clone.clone()
]);
}
continue;
}
if (typeof ruleWithVariant === "string") {
collectedFormats.push({
format: ruleWithVariant,
respectPrefix
});
}
if (ruleWithVariant === null) {
continue;
}
// We had to backup selectors, therefore we assume that somebody touched
// `container` or `modifySelectors`. Let's see if they did, so that we
// can restore the selectors, and collect the format strings.
if (clone.raws.neededBackup) {
delete clone.raws.neededBackup;
clone.walkRules((rule)=>{
let before = rule.raws.originalSelector;
if (!before) return;
delete rule.raws.originalSelector;
if (before === rule.selector) return; // No mutation happened
let modified = rule.selector;
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = (0, _postcssselectorparser.default)((selectors)=>{
selectors.walkClasses((classNode)=>{
classNode.value = `${variant}${context.tailwindConfig.separator}${classNode.value}`;
});
}).processSync(before);
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
collectedFormats.push({
format: modified.replace(rebuiltBase, "&"),
respectPrefix
});
rule.selector = before;
});
}
// This tracks the originating layer for the variant
// For example:
// .sm:underline {} is a variant of something in the utilities layer
// .sm:container {} is a variant of the container component
clone.nodes[0].raws.tailwind = {
...clone.nodes[0].raws.tailwind,
parentLayer: meta.layer
};
var _meta_collectedFormats;
let withOffset = [
{
...meta,
sort: variantSort | meta.sort
sort: context.offsets.applyVariantOffset(meta.sort, variantSort, Object.assign(args, context.variantOptions.get(variant))),
collectedFormats: ((_meta_collectedFormats = meta.collectedFormats) !== null && _meta_collectedFormats !== void 0 ? _meta_collectedFormats : []).concat(collectedFormats)
},

@@ -178,6 +441,5 @@ clone.nodes[0]

}
function parseRules(rule, cache, options = {
}) {
function parseRules(rule, cache, options = {}) {
// PostCSS node
if (!(0, _isPlainObject).default(rule) && !Array.isArray(rule)) {
if (!(0, _isPlainObject.default)(rule) && !Array.isArray(rule)) {
return [

@@ -196,3 +458,3 @@ [

if (!cache.has(rule)) {
cache.set(rule, (0, _parseObjectStyles).default(rule));
cache.set(rule, (0, _parseObjectStyles.default)(rule));
}

@@ -204,2 +466,83 @@ return [

}
const IS_VALID_PROPERTY_NAME = /^[a-z_-]/;
function isValidPropName(name) {
return IS_VALID_PROPERTY_NAME.test(name);
}
/**
* @param {string} declaration
* @returns {boolean}
*/ function looksLikeUri(declaration) {
// Quick bailout for obvious non-urls
// This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
if (!declaration.includes("://")) {
return false;
}
try {
const url = new URL(declaration);
return url.scheme !== "" && url.host !== "";
} catch (err) {
// Definitely not a valid url
return false;
}
}
function isParsableNode(node) {
let isParsable = true;
node.walkDecls((decl)=>{
if (!isParsableCssValue(decl.prop, decl.value)) {
isParsable = false;
return false;
}
});
return isParsable;
}
function isParsableCssValue(property, value) {
// We don't want to to treat [https://example.com] as a custom property
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
// So we short-circuit here by checking if the custom property looks like a url
if (looksLikeUri(`${property}:${value}`)) {
return false;
}
try {
_postcss.default.parse(`a{${property}:${value}}`).toResult();
return true;
} catch (err) {
return false;
}
}
function extractArbitraryProperty(classCandidate, context) {
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) {
return null;
}
if (!isValidPropName(property)) {
return null;
}
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) {
return null;
}
let normalized = (0, _dataTypes.normalize)(value, {
property
});
if (!isParsableCssValue(property, normalized)) {
return null;
}
let sort = context.offsets.arbitraryProperty(classCandidate);
return [
[
{
sort,
layer: "utilities",
options: {
respectImportant: true
}
},
()=>({
[(0, _nameClass.asClass)(classCandidate)]: {
[property]: normalized
}
})
]
];
}
function* resolveMatchedPlugins(classCandidate, context) {

@@ -209,10 +552,19 @@ if (context.candidateRuleMap.has(classCandidate)) {

context.candidateRuleMap.get(classCandidate),
'DEFAULT'
"DEFAULT"
];
}
yield* function*(arbitraryPropertyRule) {
if (arbitraryPropertyRule !== null) {
yield [
arbitraryPropertyRule,
"DEFAULT"
];
}
}(extractArbitraryProperty(classCandidate, context));
let candidatePrefix = classCandidate;
let negative = false;
const twConfigPrefix = context.tailwindConfig.prefix || '';
const twConfigPrefix = context.tailwindConfig.prefix;
const twConfigPrefixLen = twConfigPrefix.length;
if (candidatePrefix[twConfigPrefixLen] === '-') {
const hasMatchingPrefix = candidatePrefix.startsWith(twConfigPrefix) || candidatePrefix.startsWith(`-${twConfigPrefix}`);
if (candidatePrefix[twConfigPrefixLen] === "-" && hasMatchingPrefix) {
negative = true;

@@ -224,3 +576,3 @@ candidatePrefix = twConfigPrefix + candidatePrefix.slice(twConfigPrefixLen + 1);

context.candidateRuleMap.get(candidatePrefix),
'-DEFAULT'
"-DEFAULT"
];

@@ -234,3 +586,2 @@ }

];
return;
}

@@ -240,4 +591,21 @@ }

function splitWithSeparator(input, separator) {
return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'));
if (input === _sharedState.NOT_ON_DEMAND) {
return [
_sharedState.NOT_ON_DEMAND
];
}
return (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(input, separator);
}
function* recordCandidates(matches, classCandidate) {
for (const match of matches){
var _match__options;
var _match__options_preserveSource;
match[1].raws.tailwind = {
...match[1].raws.tailwind,
classCandidate,
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
};
yield match;
}
}
function* resolveMatches(candidate, context) {

@@ -247,3 +615,3 @@ let separator = context.tailwindConfig.separator;

let important = false;
if (classCandidate.startsWith('!')) {
if (classCandidate.startsWith("!")) {
important = true;

@@ -270,3 +638,3 @@ classCandidate = classCandidate.slice(1);

let matchesPerPlugin = [];
if (typeof plugin === 'function') {
if (typeof plugin === "function") {
for (let ruleSet of [].concat(plugin(modifier, {

@@ -289,3 +657,3 @@ isOnlyPlugin

}
} else if (modifier === 'DEFAULT' || modifier === '-DEFAULT') {
} else if (modifier === "DEFAULT" || modifier === "-DEFAULT") {
let ruleSet = plugin;

@@ -307,53 +675,96 @@ let [rules, options] = parseRules(ruleSet, context.postCssNodeCache);

if (matchesPerPlugin.length > 0) {
var ref;
typesByMatches.set(matchesPerPlugin, (ref = sort.options) === null || ref === void 0 ? void 0 : ref.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) {
typesByMatches.set(matchesPerPlugin, matchingTypes);
}
matches.push(matchesPerPlugin);
}
}
// Only keep the result of the very first plugin if we are dealing with
// arbitrary values, to protect against ambiguity.
if (isArbitraryValue(modifier) && matches.length > 1) {
var ref;
let typesPerPlugin = matches.map((match)=>new Set([
...(ref = typesByMatches.get(match)) !== null && ref !== void 0 ? ref : []
])
);
// Remove duplicates, so that we can detect proper unique types for each plugin.
for (let pluginTypes of typesPerPlugin){
for (let type of pluginTypes){
let removeFromOwnGroup = false;
for (let otherGroup of typesPerPlugin){
if (pluginTypes === otherGroup) continue;
if (otherGroup.has(type)) {
otherGroup.delete(type);
removeFromOwnGroup = true;
if (isArbitraryValue(modifier)) {
if (matches.length > 1) {
// Partition plugins in 2 categories so that we can start searching in the plugins that
// don't have `any` as a type first.
let [withAny, withoutAny] = matches.reduce((group, plugin)=>{
let hasAnyType = plugin.some(([{ options }])=>options.types.some(({ type })=>type === "any"));
if (hasAnyType) {
group[0].push(plugin);
} else {
group[1].push(plugin);
}
return group;
}, [
[],
[]
]);
function findFallback(matches) {
// If only a single plugin matches, let's take that one
if (matches.length === 1) {
return matches[0];
}
// Otherwise, find the plugin that creates a valid rule given the arbitrary value, and
// also has the correct type which preferOnConflicts the plugin in case of clashes.
return matches.find((rules)=>{
let matchingTypes = typesByMatches.get(rules);
return rules.some(([{ options }, rule])=>{
if (!isParsableNode(rule)) {
return false;
}
return options.types.some(({ type , preferOnConflict })=>matchingTypes.includes(type) && preferOnConflict);
});
});
}
var _findFallback;
// Try to find a fallback plugin, because we already know that multiple plugins matched for
// the given arbitrary value.
let fallback = (_findFallback = findFallback(withoutAny)) !== null && _findFallback !== void 0 ? _findFallback : findFallback(withAny);
if (fallback) {
matches = [
fallback
];
} else {
var _typesByMatches_get;
let typesPerPlugin = matches.map((match)=>new Set([
...(_typesByMatches_get = typesByMatches.get(match)) !== null && _typesByMatches_get !== void 0 ? _typesByMatches_get : []
]));
// Remove duplicates, so that we can detect proper unique types for each plugin.
for (let pluginTypes of typesPerPlugin){
for (let type of pluginTypes){
let removeFromOwnGroup = false;
for (let otherGroup of typesPerPlugin){
if (pluginTypes === otherGroup) continue;
if (otherGroup.has(type)) {
otherGroup.delete(type);
removeFromOwnGroup = true;
}
}
if (removeFromOwnGroup) pluginTypes.delete(type);
}
}
if (removeFromOwnGroup) pluginTypes.delete(type);
let messages = [];
for (let [idx, group] of typesPerPlugin.entries()){
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("[", `[${type}:`)}\` for \`${rules.trim()}\``);
break;
}
}
_log.default.warn([
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
...messages,
`If this is content and not a class, replace it with \`${candidate.replace("[", "&lsqb;").replace("]", "&rsqb;")}\` to silence this warning.`
]);
continue;
}
}
let messages = [];
for (let [idx, group] of typesPerPlugin.entries()){
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('[', `[${type}:`)}\` for \`${rules.trim()}\``);
break;
}
}
_log.default.warn([
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
...messages,
`If this is content and not a class, replace it with \`${candidate.replace('[', '&lsqb;').replace(']', '&rsqb;')}\` to silence this warning.`,
]);
continue;
matches = matches.map((list)=>list.filter((match)=>isParsableNode(match[1])));
}
matches = applyPrefix(matches.flat(), context);
matches = matches.flat();
matches = Array.from(recordCandidates(matches, classCandidate));
matches = applyPrefix(matches, context);
if (important) {
matches = applyImportant(matches, context);
matches = applyImportant(matches, classCandidate);
}

@@ -364,2 +775,17 @@ for (let variant of variants){

for (let match of matches){
match[1].raws.tailwind = {
...match[1].raws.tailwind,
candidate
};
// Apply final format selector
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;
}
yield match;

@@ -369,7 +795,93 @@ }

}
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) {
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes';
return rule.parent && rule.parent.type === "atrule" && rule.parent.name === "keyframes";
}
function generateRules(candidates, context) {
function getImportantStrategy(important) {
if (important === true) {
return (rule)=>{
if (inKeyframes(rule)) {
return;
}
rule.walkDecls((d)=>{
if (d.parent.type === "rule" && !inKeyframes(d.parent)) {
d.important = true;
}
});
};
}
if (typeof important === "string") {
return (rule)=>{
if (inKeyframes(rule)) {
return;
}
rule.selectors = rule.selectors.map((selector)=>{
return (0, _applyImportantSelector.applyImportantSelector)(selector, important);
});
};
}
}
function generateRules(candidates, context, isSorting = false) {
let allRules = [];
let strategy = getImportantStrategy(context.tailwindConfig.important);
for (let candidate of candidates){

@@ -379,4 +891,4 @@ if (context.notClassCache.has(candidate)) {

}
if (context.classCache.has(candidate)) {
allRules.push(context.classCache.get(candidate));
if (context.candidateRuleCache.has(candidate)) {
allRules = allRules.concat(Array.from(context.candidateRuleCache.get(candidate)));
continue;

@@ -390,13 +902,8 @@ }

context.classCache.set(candidate, matches);
allRules.push(matches);
}
return allRules.flat(1).map(([{ sort , layer , options }, rule])=>{
if (options.respectImportant) {
if (context.tailwindConfig.important === true) {
rule.walkDecls((d)=>{
if (d.parent.type === 'rule' && !inKeyframes(d.parent)) {
d.important = true;
}
});
} else if (typeof context.tailwindConfig.important === 'string') {
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);
for (const match of matches){
let [{ sort , options }, rule] = match;
if (options.respectImportant && strategy) {
let container = _postcss.default.root({

@@ -407,23 +914,20 @@ nodes: [

});
container.walkRules((r)=>{
if (inKeyframes(r)) {
return;
}
r.selectors = r.selectors.map((selector)=>{
return `${context.tailwindConfig.important} ${selector}`;
});
});
container.walkRules(strategy);
rule = container.nodes[0];
}
// 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);
context.ruleCache.add(newEntry);
allRules.push(newEntry);
}
return [
sort | context.layerOrder[layer],
rule
];
});
}
return allRules;
}
function isArbitraryValue(input) {
return input.startsWith('[') && input.endsWith(']');
return input.startsWith("[") && input.endsWith("]");
}
exports.resolveMatches = resolveMatches;
exports.generateRules = generateRules;

@@ -5,8 +5,11 @@ "use strict";

});
exports.default = getModuleDependencies;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _resolve = _interopRequireDefault(require("resolve"));
var _detective = _interopRequireDefault(require("detective"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return getModuleDependencies;
}
});
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 : {

@@ -16,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()));
}

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = normalizeTailwindDirectives;
var _log = _interopRequireDefault(require("../util/log"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return normalizeTailwindDirectives;
}
});
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -16,21 +21,25 @@ default: obj

let layerDirectives = new Set();
let applyDirectives = new Set();
root.walkAtRules((atRule)=>{
if (atRule.name === 'import') {
if (atRule.name === "apply") {
applyDirectives.add(atRule);
}
if (atRule.name === "import") {
if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") {
atRule.name = 'tailwind';
atRule.params = 'base';
atRule.name = "tailwind";
atRule.params = "base";
} else if (atRule.params === '"tailwindcss/components"' || atRule.params === "'tailwindcss/components'") {
atRule.name = 'tailwind';
atRule.params = 'components';
atRule.name = "tailwind";
atRule.params = "components";
} else if (atRule.params === '"tailwindcss/utilities"' || atRule.params === "'tailwindcss/utilities'") {
atRule.name = 'tailwind';
atRule.params = 'utilities';
atRule.name = "tailwind";
atRule.params = "utilities";
} else if (atRule.params === '"tailwindcss/screens"' || atRule.params === "'tailwindcss/screens'" || atRule.params === '"tailwindcss/variants"' || atRule.params === "'tailwindcss/variants'") {
atRule.name = 'tailwind';
atRule.params = 'variants';
atRule.name = "tailwind";
atRule.params = "variants";
}
}
if (atRule.name === 'tailwind') {
if (atRule.params === 'screens') {
atRule.params = 'variants';
if (atRule.name === "tailwind") {
if (atRule.params === "screens") {
atRule.params = "variants";
}

@@ -40,13 +49,14 @@ tailwindDirectives.add(atRule.params);

if ([
'layer',
'responsive',
'variants'
"layer",
"responsive",
"variants"
].includes(atRule.name)) {
if ([
'responsive',
'variants'
"responsive",
"variants"
].includes(atRule.name)) {
_log.default.warn(`${atRule.name}-at-rule-deprecated`, [
`The \`@${atRule.name}\` directive has been deprecated in Tailwind CSS v3.0.`,
`Use \`@layer utilities\` or \`@layer components\` instead.`,
`Use \`@layer utilities\` or \`@layer components\` instead.`,
"https://tailwindcss.com/docs/upgrade-guide#replace-variants-with-layer"
]);

@@ -57,8 +67,8 @@ }

});
if (!tailwindDirectives.has('base') || !tailwindDirectives.has('components') || !tailwindDirectives.has('utilities')) {
if (!tailwindDirectives.has("base") || !tailwindDirectives.has("components") || !tailwindDirectives.has("utilities")) {
for (let rule of layerDirectives){
if (rule.name === 'layer' && [
'base',
'components',
'utilities'
if (rule.name === "layer" && [
"base",
"components",
"utilities"
].includes(rule.params)) {

@@ -68,9 +78,9 @@ if (!tailwindDirectives.has(rule.params)) {

}
} else if (rule.name === 'responsive') {
if (!tailwindDirectives.has('utilities')) {
throw rule.error('`@responsive` is used but `@tailwind utilities` is missing.');
} else if (rule.name === "responsive") {
if (!tailwindDirectives.has("utilities")) {
throw rule.error("`@responsive` is used but `@tailwind utilities` is missing.");
}
} else if (rule.name === 'variants') {
if (!tailwindDirectives.has('utilities')) {
throw rule.error('`@variants` is used but `@tailwind utilities` is missing.');
} else if (rule.name === "variants") {
if (!tailwindDirectives.has("utilities")) {
throw rule.error("`@variants` is used but `@tailwind utilities` is missing.");
}

@@ -80,3 +90,6 @@ }

}
return tailwindDirectives;
return {
tailwindDirectives,
applyDirectives
};
}

@@ -5,8 +5,20 @@ "use strict";

});
exports.default = resolveDefaultsAtRules;
exports.elementSelectorParser = void 0;
var _postcss = _interopRequireDefault(require("postcss"));
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
var _featureFlags = require("../featureFlags");
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
elementSelectorParser: function() {
return elementSelectorParser;
},
default: function() {
return resolveDefaultsAtRules;
}
});
const _postcss = /*#__PURE__*/ _interop_require_default(require("postcss"));
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
const _featureFlags = require("../featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -18,5 +30,5 @@ default: obj

id (node) {
return _postcssSelectorParser.default.attribute({
attribute: 'id',
operator: '=',
return _postcssselectorparser.default.attribute({
attribute: "id",
operator: "=",
value: node.value,

@@ -30,3 +42,3 @@ quoteMark: '"'

// Keep non-pseudo nodes
if (node.type !== 'pseudo') return true;
if (node.type !== "pseudo") return true;
// Keep pseudo nodes that have subnodes

@@ -37,26 +49,24 @@ // E.g.: `:not()` contains subnodes inside the parentheses

// This implicitly means that we ignore pseudo `classes`
return node.value.startsWith('::') || [
':before',
':after',
':first-line',
':first-letter'
return node.value.startsWith("::") || [
":before",
":after",
":first-line",
":first-letter"
].includes(node.value);
}).reverse();
let searchFor = new Set([
'tag',
'class',
'id',
'attribute'
"tag",
"class",
"id",
"attribute"
]);
let splitPointIdx = rest.findIndex((n)=>searchFor.has(n.type)
);
if (splitPointIdx === -1) return rest.reverse().join('').trim();
let splitPointIdx = rest.findIndex((n)=>searchFor.has(n.type));
if (splitPointIdx === -1) return rest.reverse().join("").trim();
let node = rest[splitPointIdx];
let bestNode = getNode[node.type] ? getNode[node.type](node) : node;
rest = rest.slice(0, splitPointIdx);
let combinatorIdx = rest.findIndex((n)=>n.type === 'combinator' && n.value === '>'
);
let combinatorIdx = rest.findIndex((n)=>n.type === "combinator" && n.value === ">");
if (combinatorIdx !== -1) {
rest.splice(0, combinatorIdx);
rest.unshift(_postcssSelectorParser.default.universal());
rest.unshift(_postcssselectorparser.default.universal());
}

@@ -66,12 +76,10 @@ return [

...rest.reverse()
].join('').trim();
].join("").trim();
}
let elementSelectorParser = (0, _postcssSelectorParser).default((selectors)=>{
let elementSelectorParser = (0, _postcssselectorparser.default)((selectors)=>{
return selectors.map((s)=>{
let nodes = s.split((n)=>n.type === 'combinator' && n.value === ' '
).pop();
let nodes = s.split((n)=>n.type === "combinator" && n.value === " ").pop();
return minimumImpactSelector(nodes);
});
});
exports.elementSelectorParser = elementSelectorParser;
let cache = new Map();

@@ -87,4 +95,4 @@ function extractElementSelector(selector) {

let variableNodeMap = new Map();
let universals = new Set();
root.walkAtRules('defaults', (rule)=>{
/** @type {Set<import('postcss').AtRule>} */ let universals = new Set();
root.walkAtRules("defaults", (rule)=>{
if (rule.nodes && rule.nodes.length > 0) {

@@ -101,32 +109,66 @@ universals.add(rule);

});
for (let universal of universals){
let selectors = new Set();
var ref;
let rules = (ref = variableNodeMap.get(universal.params)) !== null && ref !== void 0 ? ref : [];
for (let rule of rules){
for (let selector of extractElementSelector(rule.selector)){
selectors.add(selector);
if ((0, _featureFlags.flagEnabled)(tailwindConfig, "optimizeUniversalDefaults")) {
for (let universal of universals){
/** @type {Map<string, Set<string>>} */ let selectorGroups = new Map();
var _variableNodeMap_get;
let rules = (_variableNodeMap_get = variableNodeMap.get(universal.params)) !== null && _variableNodeMap_get !== void 0 ? _variableNodeMap_get : [];
for (let rule of rules){
for (let selector of extractElementSelector(rule.selector)){
// If selector contains a vendor prefix after a pseudo element or class,
// we consider them separately because merging the declarations into
// a single rule will cause browsers that do not understand the
// vendor prefix to throw out the whole rule
// Additionally if a selector contains `:has` we also consider
// it separately because FF only recently gained support for it
let selectorGroupName = selector.includes(":-") || selector.includes("::-") || selector.includes(":has") ? selector : "__DEFAULT__";
var _selectorGroups_get;
let selectors = (_selectorGroups_get = selectorGroups.get(selectorGroupName)) !== null && _selectorGroups_get !== void 0 ? _selectorGroups_get : new Set();
selectorGroups.set(selectorGroupName, selectors);
selectors.add(selector);
}
}
if ((0, _featureFlags.flagEnabled)(tailwindConfig, "optimizeUniversalDefaults")) {
if (selectorGroups.size === 0) {
universal.remove();
continue;
}
for (let [, selectors] of selectorGroups){
let universalRule = _postcss.default.rule({
source: universal.source
});
universalRule.selectors = [
...selectors
];
universalRule.append(universal.nodes.map((node)=>node.clone()));
universal.before(universalRule);
}
}
universal.remove();
}
if (selectors.size === 0) {
} else if (universals.size) {
let universalRule = _postcss.default.rule({
selectors: [
"*",
"::before",
"::after"
]
});
for (let universal of universals){
universalRule.append(universal.nodes);
if (!universalRule.parent) {
universal.before(universalRule);
}
if (!universalRule.source) {
universalRule.source = universal.source;
}
universal.remove();
continue;
}
let universalRule = _postcss.default.rule();
if ((0, _featureFlags).flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
universalRule.selectors = [
...selectors
];
} else {
universalRule.selectors = [
'*',
'::before',
'::after'
];
}
universalRule.append(universal.nodes);
universal.before(universalRule);
universal.remove();
let backdropRule = universalRule.clone({
selectors: [
"::backdrop"
]
});
universalRule.after(backdropRule);
}
};
}

@@ -5,24 +5,52 @@ "use strict";

});
exports.getFileModifiedMap = getFileModifiedMap;
exports.createContext = createContext;
exports.getContext = getContext;
var _fs = _interopRequireDefault(require("fs"));
var _url = _interopRequireDefault(require("url"));
var _postcss = _interopRequireDefault(require("postcss"));
var _dlv = _interopRequireDefault(require("dlv"));
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
var _transformThemeValue = _interopRequireDefault(require("../util/transformThemeValue"));
var _parseObjectStyles = _interopRequireDefault(require("../util/parseObjectStyles"));
var _prefixSelector = _interopRequireDefault(require("../util/prefixSelector"));
var _isPlainObject = _interopRequireDefault(require("../util/isPlainObject"));
var _escapeClassName = _interopRequireDefault(require("../util/escapeClassName"));
var _nameClass = _interopRequireWildcard(require("../util/nameClass"));
var _pluginUtils = require("../util/pluginUtils");
var _bigSign = _interopRequireDefault(require("../util/bigSign"));
var _corePlugins = require("../corePlugins");
var sharedState = _interopRequireWildcard(require("./sharedState"));
var _toPath = require("../util/toPath");
var _log = _interopRequireDefault(require("../util/log"));
var _negateValue = _interopRequireDefault(require("../util/negateValue"));
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
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__*/ _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__*/ _interop_require_wildcard(require("./sharedState"));
const _toPath = require("../util/toPath");
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 _cacheInvalidation = require("./cacheInvalidation.js");
const _offsets = require("./offsets.js");
const _featureFlags = require("../featureFlags.js");
const _formatVariantSelector = require("../util/formatVariantSelector");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -32,27 +60,110 @@ default: obj

}
function _interopRequireWildcard(obj) {
if (obj && obj.__esModule) {
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
} else {
var newObj = {
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
if (obj != null) {
for(var key in obj){
if (Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {
};
if (desc.get || desc.set) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
newObj.default = obj;
return newObj;
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
function insertInto(list, value, { before =[] } = {
}) {
const INTERNAL_FEATURES = Symbol();
const VARIANT_TYPES = {
AddVariant: Symbol.for("ADD_VARIANT"),
MatchVariant: Symbol.for("MATCH_VARIANT")
};
const VARIANT_INFO = {
Base: 1 << 0,
Dynamic: 1 << 1
};
function prefix(context, selector) {
let prefix = context.tailwindConfig.prefix;
return typeof prefix === "function" ? prefix(selector) : prefix + selector;
}
function normalizeOptionTypes({ type ="any" , ...options }) {
let types = [].concat(type);
return {
...options,
types: types.map((type)=>{
if (Array.isArray(type)) {
return {
type: type[0],
...type[1]
};
}
return {
type,
preferOnConflict: false
};
})
};
}
function parseVariantFormatString(input) {
/** @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 === "}") {
// Nested rule: end
if (--depth < 0) {
throw new Error(`Your { and } are unbalanced.`);
}
parts.push(current.trim());
current = "";
} else {
// Normal character
current += char;
}
}
if (current.length > 0) {
parts.push(current.trim());
}
parts = parts.filter((part)=>part !== "");
return parts;
}
function insertInto(list, value, { before =[] } = {}) {
before = [].concat(before);

@@ -78,9 +189,12 @@ if (before.length <= 0) {

return styles.flatMap((style)=>{
let isNode = !Array.isArray(style) && !(0, _isPlainObject).default(style);
return isNode ? style : (0, _parseObjectStyles).default(style);
let isNode = !Array.isArray(style) && !(0, _isPlainObject.default)(style);
return isNode ? style : (0, _parseObjectStyles.default)(style);
});
}
function getClasses(selector) {
let parser = (0, _postcssSelectorParser).default((selectors)=>{
function getClasses(selector, mutate) {
let parser = (0, _postcssselectorparser.default)((selectors)=>{
let allClasses = [];
if (mutate) {
mutate(selectors);
}
selectors.walkClasses((classNode)=>{

@@ -93,24 +207,43 @@ allClasses.push(classNode.value);

}
function extractCandidates(node) {
/**
* 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 = [];
if (node.type === 'rule') {
for (let selector of node.selectors){
let classCandidates = getClasses(selector);
// At least one of the selectors contains non-"on-demandable" candidates.
if (classCandidates.length === 0) return [];
classes = [
...classes,
...classCandidates
];
let selectors = [];
if (node.type === "rule") {
// 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;
}
return classes;
for (let classCandidate of classCandidates){
classes.push(classCandidate);
}
}
if (node.type === 'atrule') {
node.walkRules((rule)=>{
classes = [
...classes,
...rule.selectors.flatMap((selector)=>getClasses(selector)
)
];
});
if (depth === 0) {
return [
state.containsNonOnDemandable || classes.length === 0,
classes
];
}

@@ -122,12 +255,10 @@ return classes;

let nodeMap = new Map();
let candidates = extractCandidates(node);
// If this isn't "on-demandable", assign it a universal candidate.
if (candidates.length === 0) {
return [
[
'*',
node
]
];
let [containsNonOnDemandableSelectors, candidates] = extractCandidates(node);
// If this isn't "on-demandable", assign it a universal candidate to always include it.
if (containsNonOnDemandableSelectors) {
candidates.unshift(_sharedState.NOT_ON_DEMAND);
}
// However, it could be that it also contains "on-demandable" candidates.
// E.g.: `span, .foo {}`, in that case it should still be possible to use
// `@apply foo` for example.
return candidates.map((c)=>{

@@ -144,74 +275,42 @@ if (!nodeMap.has(node)) {

}
let matchingBrackets = new Map([
[
'{',
'}'
],
[
'[',
']'
],
[
'(',
')'
],
]);
let inverseMatchingBrackets = new Map(Array.from(matchingBrackets.entries()).map(([k, v])=>[
v,
k
]
));
let quotes = new Set([
'"',
"'",
'`'
]);
// Arbitrary values must contain balanced brackets (), [] and {}. Escaped
// values don't count, and brackets inside quotes also don't count.
//
// E.g.: w-[this-is]w-[weird-and-invalid]
// E.g.: w-[this-is\\]w-\\[weird-but-valid]
// E.g.: content-['this-is-also-valid]-weirdly-enough']
function isValidArbitraryValue(value) {
let stack = [];
let inQuotes = false;
for(let i = 0; i < value.length; i++){
let char = value[i];
// Non-escaped quotes allow us to "allow" anything in between
if (quotes.has(char) && value[i - 1] !== '\\') {
inQuotes = !inQuotes;
function isValidVariantFormatString(format) {
return format.startsWith("@") || format.includes("&");
}
function parseVariant(variant) {
variant = variant.replace(/\n+/g, "").replace(/\s{1,}/g, " ").trim();
let fns = parseVariantFormatString(variant).map((str)=>{
if (!str.startsWith("@")) {
return ({ format })=>format(str);
}
if (inQuotes) continue;
if (value[i - 1] === '\\') continue; // Escaped
if (matchingBrackets.has(char)) {
stack.push(char);
} else if (inverseMatchingBrackets.has(char)) {
let inverse = inverseMatchingBrackets.get(char);
// Nothing to pop from, therefore it is unbalanced
if (stack.length <= 0) {
return false;
}
// Popped value must match the inverse value, otherwise it is unbalanced
if (stack.pop() !== inverse) {
return false;
}
let [, name, params] = /@(\S*)( .+|[({].*)?/g.exec(str);
var _params_trim;
return ({ wrap })=>{
return wrap(_postcss.default.atRule({
name,
params: (_params_trim = params === null || params === void 0 ? void 0 : params.trim()) !== null && _params_trim !== void 0 ? _params_trim : ""
}));
};
}).reverse();
return (api)=>{
for (let fn of fns){
fn(api);
}
}
// If there is still something on the stack, it is also unbalanced
if (stack.length > 0) {
return false;
}
// All good, totally balanced!
return true;
};
}
function buildPluginApi(tailwindConfig, context, { variantList , variantMap , offsets , classList }) {
/**
*
* @param {any} tailwindConfig
* @param {any} context
* @param {object} param2
* @param {Offsets} param2.offsets
*/ function buildPluginApi(tailwindConfig, context, { variantList , variantMap , offsets , classList }) {
function getConfigValue(path, defaultValue) {
return path ? (0, _dlv).default(tailwindConfig, path, defaultValue) : tailwindConfig;
return path ? (0, _dlv.default)(tailwindConfig, path, defaultValue) : tailwindConfig;
}
function applyConfiguredPrefix(selector) {
return (0, _prefixSelector).default(tailwindConfig.prefix, selector);
return (0, _prefixSelector.default)(tailwindConfig.prefix, selector);
}
function prefixIdentifier(identifier, options) {
if (identifier === '*') {
return '*';
if (identifier === _sharedState.NOT_ON_DEMAND) {
return _sharedState.NOT_ON_DEMAND;
}

@@ -221,14 +320,14 @@ if (!options.respectPrefix) {

}
if (typeof context.tailwindConfig.prefix === 'function') {
return (0, _prefixSelector).default(context.tailwindConfig.prefix, `.${identifier}`).substr(1);
}
return context.tailwindConfig.prefix + identifier;
}
return {
addVariant (variantName, variantFunctions, options = {
}) {
variantFunctions = [].concat(variantFunctions);
insertInto(variantList, variantName, options);
variantMap.set(variantName, variantFunctions);
},
function resolveThemeValue(path, defaultValue, opts = {}) {
let parts = (0, _toPath.toPath)(path);
let value = getConfigValue([
"theme",
...parts
], defaultValue);
return (0, _transformThemeValue.default)(parts[0])(value, opts);
}
let variantIdentifier = 0;
let api = {
postcss: _postcss.default,

@@ -238,11 +337,3 @@ prefix: applyConfiguredPrefix,

config: getConfigValue,
theme (path, defaultValue) {
const [pathRoot, ...subPaths] = (0, _toPath).toPath(path);
const value = getConfigValue([
'theme',
pathRoot,
...subPaths
], defaultValue);
return (0, _transformThemeValue).default(pathRoot)(value);
},
theme: resolveThemeValue,
corePlugins: (path)=>{

@@ -253,3 +344,3 @@ if (Array.isArray(tailwindConfig.corePlugins)) {

return getConfigValue([
'corePlugins',
"corePlugins",
path

@@ -262,12 +353,13 @@ ], true);

},
addUserCss (userCss) {
for (let [identifier, rule] of withIdentifiers(userCss)){
let offset = offsets.user++;
if (!context.candidateRuleMap.has(identifier)) {
context.candidateRuleMap.set(identifier, []);
addBase (base) {
for (let [identifier, rule] of withIdentifiers(base)){
let prefixedIdentifier = prefixIdentifier(identifier, {});
let offset = offsets.create("base");
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, []);
}
context.candidateRuleMap.get(identifier).push([
context.candidateRuleMap.get(prefixedIdentifier).push([
{
sort: offset,
layer: 'user'
layer: "base"
},

@@ -278,7 +370,11 @@ rule

},
addBase (base) {
for (let [identifier, rule] of withIdentifiers(base)){
let prefixedIdentifier = prefixIdentifier(identifier, {
});
let offset = offsets.base++;
/**
* @param {string} group
* @param {Record<string, string | string[]>} declarations
*/ addDefaults (group, declarations) {
const groups = {
[`@defaults ${group}`]: declarations
};
for (let [identifier, rule] of withIdentifiers(groups)){
let prefixedIdentifier = prefixIdentifier(identifier, {});
if (!context.candidateRuleMap.has(prefixedIdentifier)) {

@@ -289,4 +385,4 @@ context.candidateRuleMap.set(prefixedIdentifier, []);

{
sort: offset,
layer: 'base'
sort: offsets.create("defaults"),
layer: "defaults"
},

@@ -299,11 +395,9 @@ rule

let defaultOptions = {
preserveSource: false,
respectPrefix: true,
respectImportant: false
};
options = Object.assign({
}, defaultOptions, Array.isArray(options) ? {
} : options);
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options);
for (let [identifier, rule] of withIdentifiers(components)){
let prefixedIdentifier = prefixIdentifier(identifier, options);
let offset = offsets.components++;
classList.add(prefixedIdentifier);

@@ -315,4 +409,4 @@ if (!context.candidateRuleMap.has(prefixedIdentifier)) {

{
sort: offset,
layer: 'components',
sort: offsets.create("components"),
layer: "components",
options

@@ -326,11 +420,9 @@ },

let defaultOptions = {
preserveSource: false,
respectPrefix: true,
respectImportant: true
};
options = Object.assign({
}, defaultOptions, Array.isArray(options) ? {
} : options);
options = Object.assign({}, defaultOptions, Array.isArray(options) ? {} : options);
for (let [identifier, rule] of withIdentifiers(utilities)){
let prefixedIdentifier = prefixIdentifier(identifier, options);
let offset = offsets.utilities++;
classList.add(prefixedIdentifier);

@@ -342,4 +434,4 @@ if (!context.candidateRuleMap.has(prefixedIdentifier)) {

{
sort: offset,
layer: 'utilities',
sort: offsets.create("utilities"),
layer: "utilities",
options

@@ -354,9 +446,10 @@ },

respectPrefix: true,
respectImportant: true
respectImportant: true,
modifiers: false
};
options = {
options = normalizeOptionTypes({
...defaultOptions,
...options
};
let offset = offsets.utilities++;
});
let offset = offsets.create("utilities");
for(let identifier in utilities){

@@ -370,18 +463,33 @@ let prefixedIdentifier = prefixIdentifier(identifier, options);

function wrapped(modifier, { isOnlyPlugin }) {
let { type ='any' } = options;
type = [].concat(type);
let [value, coercedType] = (0, _pluginUtils).coerceValue(type, modifier, options, tailwindConfig);
let [value, coercedType, utilityModifier] = (0, _pluginUtils.coerceValue)(options.types, modifier, options, tailwindConfig);
if (value === undefined) {
return [];
}
if (!type.includes(coercedType) && !isOnlyPlugin) {
return [];
if (!options.types.some(({ type })=>type === coercedType)) {
if (isOnlyPlugin) {
_log.default.warn([
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(coercedType + ":", "")}\`.`
]);
} else {
return [];
}
}
if (!isValidArbitraryValue(value)) {
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) {
return [];
}
let ruleSets = [].concat(rule(value)).filter(Boolean).map((declaration)=>({
[(0, _nameClass).default(identifier, modifier)]: declaration
})
);
let extras = {
get modifier () {
if (!options.modifiers) {
_log.default.warn(`modifier-used-without-options-for-${identifier}`, [
"Your plugin must set `modifiers: true` in its options to support modifiers."
]);
}
return utilityModifier;
}
};
let modifiersEnabled = (0, _featureFlags.flagEnabled)(tailwindConfig, "generalizedModifiers");
let ruleSets = [].concat(modifiersEnabled ? rule(value, extras) : rule(value)).filter(Boolean).map((declaration)=>({
[(0, _nameClass.default)(identifier, modifier)]: declaration
}));
return ruleSets;

@@ -392,3 +500,3 @@ }

sort: offset,
layer: 'utilities',
layer: "utilities",
options

@@ -407,9 +515,10 @@ },

respectPrefix: true,
respectImportant: false
respectImportant: false,
modifiers: false
};
options = {
options = normalizeOptionTypes({
...defaultOptions,
...options
};
let offset = offsets.components++;
});
let offset = offsets.create("components");
for(let identifier in components){

@@ -423,13 +532,11 @@ let prefixedIdentifier = prefixIdentifier(identifier, options);

function wrapped(modifier, { isOnlyPlugin }) {
let { type ='any' } = options;
type = [].concat(type);
let [value, coercedType] = (0, _pluginUtils).coerceValue(type, modifier, options, tailwindConfig);
let [value, coercedType, utilityModifier] = (0, _pluginUtils.coerceValue)(options.types, modifier, options, tailwindConfig);
if (value === undefined) {
return [];
}
if (!type.includes(coercedType)) {
if (!options.types.some(({ type })=>type === coercedType)) {
if (isOnlyPlugin) {
_log.default.warn([
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(coercedType + ':', '')}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(coercedType + ":", "")}\`.`
]);

@@ -440,9 +547,19 @@ } else {

}
if (!isValidArbitraryValue(value)) {
if (!(0, _isSyntacticallyValidPropertyValue.default)(value)) {
return [];
}
let ruleSets = [].concat(rule(value)).filter(Boolean).map((declaration)=>({
[(0, _nameClass).default(identifier, modifier)]: declaration
})
);
let extras = {
get modifier () {
if (!options.modifiers) {
_log.default.warn(`modifier-used-without-options-for-${identifier}`, [
"Your plugin must set `modifiers: true` in its options to support modifiers."
]);
}
return utilityModifier;
}
};
let modifiersEnabled = (0, _featureFlags.flagEnabled)(tailwindConfig, "generalizedModifiers");
let ruleSets = [].concat(modifiersEnabled ? rule(value, extras) : rule(value)).filter(Boolean).map((declaration)=>({
[(0, _nameClass.default)(identifier, modifier)]: declaration
}));
return ruleSets;

@@ -453,3 +570,3 @@ }

sort: offset,
layer: 'components',
layer: "components",
options

@@ -464,4 +581,86 @@ },

}
},
addVariant (variantName, variantFunctions, options = {}) {
variantFunctions = [].concat(variantFunctions).map((variantFunction)=>{
if (typeof variantFunction !== "string") {
// Safelist public API functions
return (api = {})=>{
let { args , modifySelectors , container , separator , wrap , format } = api;
let result = variantFunction(Object.assign({
modifySelectors,
container,
separator
}, options.type === VARIANT_TYPES.MatchVariant && {
args,
wrap,
format
}));
if (typeof result === "string" && !isValidVariantFormatString(result)) {
throw new Error(`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`);
}
if (Array.isArray(result)) {
return result.filter((variant)=>typeof variant === "string").map((variant)=>parseVariant(variant));
}
// result may be undefined with legacy variants that use APIs like `modifySelectors`
// result may also be a postcss node if someone was returning the result from `modifySelectors`
return result && typeof result === "string" && parseVariant(result)(api);
};
}
if (!isValidVariantFormatString(variantFunction)) {
throw new Error(`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`);
}
return parseVariant(variantFunction);
});
insertInto(variantList, variantName, options);
variantMap.set(variantName, variantFunctions);
context.variantOptions.set(variantName, options);
},
matchVariant (variant, variantFn, options) {
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 = (_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, _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;
api.addVariant(isSpecial ? `${variant}${key}` : `${variant}-${key}`, ({ args , container })=>{
return variantFn(value, modifiersEnabled ? {
modifier: args === null || args === void 0 ? void 0 : args.modifier,
container
} : {
container
});
}, {
...options,
value,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Base
});
}
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 })=>{
if ((args === null || args === void 0 ? void 0 : args.value) === _sharedState.NONE && !hasDefault) {
return null;
}
var // (JetBrains) plugins.
_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,
container
} : {
container
});
}, {
...options,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Dynamic
});
}
};
return api;
}

@@ -477,14 +676,24 @@ let fileModifiedMapCache = new WeakMap();

let changed = false;
let mtimesToCommit = new Map();
for (let file of files){
var _fs_statSync;
if (!file) continue;
let parsed = _url.default.parse(file);
let pathname = parsed.hash ? parsed.href.replace(parsed.hash, '') : parsed.href;
pathname = parsed.search ? pathname.replace(parsed.search, '') : pathname;
let newModified = _fs.default.statSync(decodeURIComponent(pathname)).mtimeMs;
let pathname = parsed.hash ? parsed.href.replace(parsed.hash, "") : parsed.href;
pathname = parsed.search ? pathname.replace(parsed.search, "") : pathname;
let newModified = (_fs_statSync = _fs.default.statSync(decodeURIComponent(pathname), {
throwIfNoEntry: false
})) === null || _fs_statSync === void 0 ? void 0 : _fs_statSync.mtimeMs;
if (!newModified) {
continue;
}
if (!fileModifiedMap.has(file) || newModified > fileModifiedMap.get(file)) {
changed = true;
}
fileModifiedMap.set(file, newModified);
mtimesToCommit.set(file, newModified);
}
return changed;
return [
changed,
mtimesToCommit
];
}

@@ -494,4 +703,4 @@ function extractVariantAtRules(node) {

if ([
'responsive',
'variants'
"responsive",
"variants"
].includes(atRule.name)) {

@@ -507,14 +716,14 @@ extractVariantAtRules(atRule);

root.each((node)=>{
if (node.type === 'atrule' && [
'responsive',
'variants'
if (node.type === "atrule" && [
"responsive",
"variants"
].includes(node.name)) {
node.name = 'layer';
node.params = 'utilities';
node.name = "layer";
node.params = "utilities";
}
});
// Walk @layer rules and treat them like plugins
root.walkAtRules('layer', (layerRule)=>{
root.walkAtRules("layer", (layerRule)=>{
extractVariantAtRules(layerRule);
if (layerRule.params === 'base') {
if (layerRule.params === "base") {
for (let node of layerRule.nodes){

@@ -528,7 +737,8 @@ layerPlugins.push(function({ addBase }) {

layerRule.remove();
} else if (layerRule.params === 'components') {
} else if (layerRule.params === "components") {
for (let node of layerRule.nodes){
layerPlugins.push(function({ addComponents }) {
addComponents(node, {
respectPrefix: false
respectPrefix: false,
preserveSource: true
});

@@ -538,7 +748,8 @@ });

layerRule.remove();
} else if (layerRule.params === 'utilities') {
} else if (layerRule.params === "utilities") {
for (let node of layerRule.nodes){
layerPlugins.push(function({ addUtilities }) {
addUtilities(node, {
respectPrefix: false
respectPrefix: false,
preserveSource: true
});

@@ -550,12 +761,2 @@ });

});
root.walkRules((rule)=>{
// At this point it is safe to include all the left-over css from the
// user's css file. This is because the `@tailwind` and `@layer` directives
// will already be handled and will be removed from the css tree.
layerPlugins.push(function({ addUserCss }) {
addUserCss(rule, {
respectPrefix: false
});
});
});
return layerPlugins;

@@ -577,3 +778,3 @@ }

}
return typeof plugin === 'function' ? plugin : plugin.handler;
return typeof plugin === "function" ? plugin : plugin.handler;
});

@@ -584,11 +785,36 @@ let layerPlugins = collectLayerPlugins(root);

let beforeVariants = [
_corePlugins.variantPlugins['pseudoElementVariants'],
_corePlugins.variantPlugins['pseudoClassVariants'],
_corePlugins.variantPlugins["childVariant"],
_corePlugins.variantPlugins["pseudoElementVariants"],
_corePlugins.variantPlugins["pseudoClassVariants"],
_corePlugins.variantPlugins["hasVariants"],
_corePlugins.variantPlugins["ariaVariants"],
_corePlugins.variantPlugins["dataVariants"]
];
let afterVariants = [
_corePlugins.variantPlugins['directionVariants'],
_corePlugins.variantPlugins['reducedMotionVariants'],
_corePlugins.variantPlugins['darkVariants'],
_corePlugins.variantPlugins['screenVariants'],
_corePlugins.variantPlugins["supportsVariants"],
_corePlugins.variantPlugins["reducedMotionVariants"],
_corePlugins.variantPlugins["prefersContrastVariants"],
_corePlugins.variantPlugins["screenVariants"],
_corePlugins.variantPlugins["orientationVariants"],
_corePlugins.variantPlugins["directionVariants"],
_corePlugins.variantPlugins["darkVariants"],
_corePlugins.variantPlugins["forcedColorsVariants"],
_corePlugins.variantPlugins["printVariant"]
];
// This is a compatibility fix for the pre 3.4 dark mode behavior
// `class` retains the old behavior, but `selector` keeps the new behavior
let isLegacyDarkMode = context.tailwindConfig.darkMode === "class" || Array.isArray(context.tailwindConfig.darkMode) && context.tailwindConfig.darkMode[0] === "class";
if (isLegacyDarkMode) {
afterVariants = [
_corePlugins.variantPlugins["supportsVariants"],
_corePlugins.variantPlugins["reducedMotionVariants"],
_corePlugins.variantPlugins["prefersContrastVariants"],
_corePlugins.variantPlugins["darkVariants"],
_corePlugins.variantPlugins["screenVariants"],
_corePlugins.variantPlugins["orientationVariants"],
_corePlugins.variantPlugins["directionVariants"],
_corePlugins.variantPlugins["forcedColorsVariants"],
_corePlugins.variantPlugins["printVariant"]
];
}
return [

@@ -605,8 +831,5 @@ ...corePluginList,

let variantMap = new Map();
let offsets = {
base: 0n,
components: 0n,
utilities: 0n,
user: 0n
};
context.variantMap = variantMap;
let offsets = new _offsets.Offsets();
context.offsets = offsets;
let classList = new Set();

@@ -628,50 +851,20 @@ let pluginApi = buildPluginApi(context.tailwindConfig, context, {

}
let highestOffset = ((args)=>args.reduce((m, e)=>e > m ? e : m
)
)([
offsets.base,
offsets.components,
offsets.utilities,
offsets.user,
]);
let reservedBits = BigInt(highestOffset.toString(2).length);
context.layerOrder = {
base: 1n << reservedBits << 0n,
components: 1n << reservedBits << 1n,
utilities: 1n << reservedBits << 2n,
user: 1n << reservedBits << 3n
};
reservedBits += 4n;
let offset = 0;
context.variantOrder = new Map(variantList.map((variant, i)=>{
let variantFunctions = variantMap.get(variant).length;
let bits = 1n << BigInt(i + offset) << reservedBits;
offset += variantFunctions - 1;
return [
variant,
bits
];
}).sort(([, a], [, z])=>(0, _bigSign).default(a - z)
));
context.minimumScreen = [
...context.variantOrder.values()
].shift();
// Make sure to record bit masks for every variant
offsets.recordVariants(variantList, (variant)=>variantMap.get(variant).length);
// Build variantMap
for (let [variantName, variantFunctions] of variantMap.entries()){
let sort = context.variantOrder.get(variantName);
context.variantMap.set(variantName, variantFunctions.map((variantFunction, idx)=>[
sort << BigInt(idx),
offsets.forVariant(variantName, idx),
variantFunction
]
));
]));
}
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) {
let checks = [];
for (let value of safelist){
if (typeof value === 'string') {
if (typeof value === "string") {
context.changedContent.push({
content: value,
extension: 'html'
extension: "html"
});

@@ -681,5 +874,6 @@ continue;

if (value instanceof RegExp) {
_log.default.warn('root-regex', [
'Regular expressions in `safelist` work differently in Tailwind CSS v3.0.',
'Update your `safelist` configuration to eliminate this warning.'
_log.default.warn("root-regex", [
"Regular expressions in `safelist` work differently in Tailwind CSS v3.0.",
"Update your `safelist` configuration to eliminate this warning.",
"https://tailwindcss.com/docs/content-configuration#safelisting-classes"
]);

@@ -692,13 +886,43 @@ continue;

let patternMatchingCount = new Map();
let prefixLength = context.tailwindConfig.prefix.length;
let checkImportantUtils = checks.some((check)=>check.pattern.source.includes("!"));
for (let util of classList){
let utils = Array.isArray(util) ? (()=>{
let [utilName, options] = util;
var ref;
return Object.keys((ref = options === null || options === void 0 ? void 0 : options.values) !== null && ref !== void 0 ? ref : {
}).map((value)=>(0, _nameClass).formatClass(utilName, value)
);
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));
if (options === null || options === void 0 ? void 0 : options.supportsNegativeValues) {
// This is the normal negated version
// e.g. `-inset-1` or `-tw-inset-1`
classes = [
...classes,
...classes.map((cls)=>"-" + cls)
];
// This is the negated version *after* the prefix
// e.g. `tw--inset-1`
// The prefix is already attached to util name
// So we add the negative after the prefix
classes = [
...classes,
...classes.map((cls)=>cls.slice(0, prefixLength) + "-" + cls.slice(prefixLength))
];
}
if (options.types.some(({ type })=>type === "color")) {
classes = [
...classes,
...classes.flatMap((cls)=>Object.keys(context.tailwindConfig.theme.opacity).map((opacity)=>`${cls}/${opacity}`))
];
}
if (checkImportantUtils && (options === null || options === void 0 ? void 0 : options.respectImportant)) {
classes = [
...classes,
...classes.map((cls)=>"!" + cls)
];
}
return classes;
})() : [
util
];
for (let util1 of utils){
for (let util of utils){
for (let { pattern , variants =[] } of checks){

@@ -711,12 +935,12 @@ // 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,
extension: 'html'
content: util,
extension: "html"
});
for (let variant of variants){
context.changedContent.push({
content: variant + context.tailwindConfig.separator + util1,
extension: 'html'
content: variant + context.tailwindConfig.separator + util,
extension: "html"
});

@@ -731,3 +955,4 @@ }

`The safelist pattern \`${regex}\` doesn't match any Tailwind CSS classes.`,
'Fix this pattern or remove it from your `safelist` configuration.',
"Fix this pattern or remove it from your `safelist` configuration.",
"https://tailwindcss.com/docs/content-configuration#safelisting-classes"
]);

@@ -737,17 +962,92 @@ }

}
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
// that don't exist on their own. This will result in them "not existing" and
// sorting could be weird since you still require them in order to make the
// host utilities work properly. (Thanks Biology)
let parasiteUtilities = [
prefix(context, darkClassName),
prefix(context, "group"),
prefix(context, "peer")
];
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(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 = (0, _generateRules.generateRules)(new Set(sorted), context, true);
rules = context.offsets.sort(rules);
let idx = BigInt(parasiteUtilities.length);
for (const [, rule] of rules){
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 _sortedClassNames_get;
let order = (_sortedClassNames_get = sortedClassNames.get(className)) !== null && _sortedClassNames_get !== void 0 ? _sortedClassNames_get : null;
let parasiteIndex = parasiteUtilities.indexOf(className);
if (order === null && parasiteIndex !== -1) {
// This will make sure that it is at the very beginning of the
// `components` layer which technically means 'before any
// components'.
order = BigInt(parasiteIndex);
}
return [
className,
order
];
});
};
// Generate a list of strings for autocompletion purposes, e.g.
// ['uppercase', 'lowercase', ...]
context.getClassList = function() {
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 : {
})){
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}`));
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
if (value == null) {
continue;
}
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);
}
}

@@ -761,10 +1061,190 @@ output.push(...negativeClasses);

};
// Generate a list of available variants with meta information of the type of variant.
context.getVariants = function getVariants() {
// We use a unique, random ID for candidate names to avoid conflicts
// We can't use characters like `_`, `:`, `@` or `.` because they might
// be used as a separator
let id = Math.random().toString(36).substring(7).toUpperCase();
let result = [];
for (let [name, options] of context.variantOptions.entries()){
if (options.variantInfo === VARIANT_INFO.Base) continue;
var _options_values;
result.push({
name,
isArbitrary: options.type === Symbol.for("MATCH_VARIANT"),
values: Object.keys((_options_values = options.values) !== null && _options_values !== void 0 ? _options_values : {}),
hasDash: name !== "@",
selectors ({ modifier , value } = {}) {
let candidate = `TAILWINDPLACEHOLDER${id}`;
let rule = _postcss.default.rule({
selector: `.${candidate}`
});
let container = _postcss.default.root({
nodes: [
rule.clone()
]
});
let before = container.toString();
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 _options_values;
let localFormatStrings = [];
var _options_values_value;
let api = {
args: {
modifier,
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
},
separator: context.tailwindConfig.separator,
modifySelectors (modifierFunction) {
// Run the modifierFunction over each rule
container.each((rule)=>{
if (rule.type !== "rule") {
return;
}
rule.selectors = rule.selectors.map((selector)=>{
return modifierFunction({
get className () {
return (0, _generateRules.getClassNameFromSelector)(selector);
},
selector
});
});
});
return container;
},
format (str) {
localFormatStrings.push(str);
},
wrap (wrapper) {
localFormatStrings.push(`@${wrapper.name} ${wrapper.params} { & }`);
},
container
};
let ruleWithVariant = fn(api);
if (localFormatStrings.length > 0) {
formatStrings.push(localFormatStrings);
}
if (Array.isArray(ruleWithVariant)) {
for (let variantFunction of ruleWithVariant){
localFormatStrings = [];
variantFunction(api);
formatStrings.push(localFormatStrings);
}
}
}
// Reverse engineer the result of the `container`
let manualFormatStrings = [];
let after = container.toString();
if (before !== after) {
// Figure out all selectors
container.walkRules((rule)=>{
let modified = rule.selector;
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = (0, _postcssselectorparser.default)((selectors)=>{
selectors.walkClasses((classNode)=>{
classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`;
});
}).processSync(modified);
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
manualFormatStrings.push(modified.replace(rebuiltBase, "&").replace(candidate, "&"));
});
// Figure out all atrules
container.walkAtRules((atrule)=>{
manualFormatStrings.push(`@${atrule.name} (${atrule.params}) { & }`);
});
}
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, opts).toString().replace(`.${candidate}`, "&"));
}
return result;
}
});
}
return result;
};
}
/**
* Mark as class as retroactively invalid
*
*
* @param {string} candidate
*/ function markInvalidUtilityCandidate(context, candidate) {
if (!context.classCache.has(candidate)) {
return;
}
// Mark this as not being a real utility
context.notClassCache.add(candidate);
// Remove it from any candidate-specific caches
context.classCache.delete(candidate);
context.applyClassCache.delete(candidate);
context.candidateRuleMap.delete(candidate);
context.candidateRuleCache.delete(candidate);
// Ensure the stylesheet gets rebuilt
context.stylesheetCache = null;
}
/**
* Mark as class as retroactively invalid
*
* @param {import('postcss').Node} node
*/ function markInvalidUtilityNode(context, node) {
let candidate = node.raws.tailwind.candidate;
if (!candidate) {
return;
}
for (const entry of context.ruleCache){
if (entry[1].raws.tailwind.candidate === candidate) {
context.ruleCache.delete(entry);
// context.postCssNodeCache.delete(node)
}
}
markInvalidUtilityCandidate(context, candidate);
}
function createContext(tailwindConfig, changedContent = [], root = _postcss.default.root()) {
var _tailwindConfig_blocklist;
let context = {
disposables: [],
ruleCache: new Set(),
candidateRuleCache: new Map(),
classCache: new Map(),
applyClassCache: new Map(),
notClassCache: new Set(),
// Seed the not class cache with the blocklist (which is only strings)
notClassCache: new Set((_tailwindConfig_blocklist = tailwindConfig.blocklist) !== null && _tailwindConfig_blocklist !== void 0 ? _tailwindConfig_blocklist : []),
postCssNodeCache: new Map(),

@@ -775,3 +1255,6 @@ candidateRuleMap: new Map(),

variantMap: new Map(),
stylesheetCache: null
stylesheetCache: null,
variantOptions: new Map(),
markInvalidUtilityCandidate: (candidate)=>markInvalidUtilityCandidate(context, candidate),
markInvalidUtilityNode: (node)=>markInvalidUtilityNode(context, node)
};

@@ -782,9 +1265,9 @@ let resolvedPlugins = resolvePlugins(context, root);

}
let contextMap = sharedState.contextMap;
let configContextMap = sharedState.configContextMap;
let contextSourcesMap = sharedState.contextSourcesMap;
let contextMap = _sharedState.contextMap;
let configContextMap = _sharedState.configContextMap;
let contextSourcesMap = _sharedState.contextSourcesMap;
function getContext(root, result, tailwindConfig, userConfigPath, tailwindConfigHash, contextDependencies) {
let sourcePath = result.opts.from;
let isConfigFile = userConfigPath !== null;
sharedState.env.DEBUG && console.log('Source path:', sourcePath);
_sharedState.env.DEBUG && console.log("Source path:", sourcePath);
let existingContext;

@@ -799,12 +1282,14 @@ if (isConfigFile && contextMap.has(sourcePath)) {

}
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
], getFileModifiedMap(existingContext));
if (!contextDependenciesChanged) {
if (!contextDependenciesChanged && !cssDidChange) {
return [
existingContext,
false
false,
mtimesToCommit
];

@@ -835,5 +1320,8 @@ }

}
sharedState.env.DEBUG && console.log('Setting up new context...');
_sharedState.env.DEBUG && console.log("Setting up new context...");
let context = createContext(tailwindConfig, [], root);
trackModified([
Object.assign(context, {
userConfigPath
});
let [, mtimesToCommit] = trackModified([
...contextDependencies

@@ -851,4 +1339,5 @@ ], getFileModifiedMap(context));

context,
true
true,
mtimesToCommit
];
}

@@ -0,1 +1,2 @@

// @ts-check
"use strict";

@@ -5,16 +6,24 @@ Object.defineProperty(exports, "__esModule", {

});
exports.default = setupTrackingContext;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
var _fastGlob = _interopRequireDefault(require("fast-glob"));
var _quickLru = _interopRequireDefault(require("quick-lru"));
var _normalizePath = _interopRequireDefault(require("normalize-path"));
var _hashConfig = _interopRequireDefault(require("../util/hashConfig"));
var _getModuleDependencies = _interopRequireDefault(require("../lib/getModuleDependencies"));
var _resolveConfig = _interopRequireDefault(require("../public/resolve-config"));
var _resolveConfigPath = _interopRequireDefault(require("../util/resolveConfigPath"));
var _sharedState = require("./sharedState");
var _setupContextUtils = require("./setupContextUtils");
var _parseDependency = _interopRequireDefault(require("../util/parseDependency"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, // DISABLE_TOUCH = TRUE
// Retrieve an existing context from cache if possible (since contexts are unique per
// source path), or set up a new one (including setting up watchers and registering
// plugins) then return it
"default", {
enumerable: true,
get: function() {
return setupTrackingContext;
}
});
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__*/ _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 : {

@@ -24,3 +33,3 @@ default: obj

}
let configPathCache = new _quickLru.default({
let configPathCache = new _quicklru.default({
maxSize: 100

@@ -33,5 +42,3 @@ });

}
let candidateFiles = tailwindConfig.content.files.filter((item)=>typeof item === 'string'
).map((contentPath)=>(0, _normalizePath).default(contentPath)
);
let candidateFiles = (0, _content.parseCandidateFiles)(context, tailwindConfig);
return candidateFilesCache.set(context, candidateFiles).get(context);

@@ -41,7 +48,6 @@ }

function getTailwindConfig(configOrPath) {
let userConfigPath = (0, _resolveConfigPath).default(configOrPath);
let userConfigPath = (0, _resolveConfigPath.default)(configOrPath);
if (userConfigPath !== null) {
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;

@@ -66,7 +72,7 @@ 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));
let newHash = (0, _hashConfig).default(newConfig);
let newConfig = (0, _validateConfig.validateConfig)((0, _resolveconfig.default)((0, _loadconfig.loadConfig)(userConfigPath)));
let newHash = (0, _hashConfig.default)(newConfig);
configPathCache.set(userConfigPath, [

@@ -85,43 +91,13 @@ newConfig,

}
var _configOrPath_config, _ref;
// It's a plain object, not a path
let newConfig = (0, _resolveConfig).default(configOrPath.config === undefined ? configOrPath : configOrPath.config);
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 [
newConfig,
null,
(0, _hashConfig).default(newConfig),
(0, _hashConfig.default)(newConfig),
[]
];
}
function resolvedChangedContent(context, candidateFiles, fileModifiedMap) {
let changedContent = context.tailwindConfig.content.files.filter((item)=>typeof item.raw === 'string'
).map(({ raw , extension ='html' })=>({
content: raw,
extension
})
);
for (let changedFile of resolveChangedFiles(candidateFiles, fileModifiedMap)){
let content = _fs.default.readFileSync(changedFile, 'utf8');
let extension = _path.default.extname(changedFile).slice(1);
changedContent.push({
content,
extension
});
}
return changedContent;
}
function resolveChangedFiles(candidateFiles, fileModifiedMap) {
let changedFiles = new Set();
_sharedState.env.DEBUG && console.time('Finding changed files');
let files = _fastGlob.default.sync(candidateFiles);
for (let file of files){
let prevModified = fileModifiedMap.has(file) ? fileModifiedMap.get(file) : -Infinity;
let modified = _fs.default.statSync(file).mtimeMs;
if (modified > prevModified) {
changedFiles.add(file);
fileModifiedMap.set(file, modified);
}
}
_sharedState.env.DEBUG && console.timeEnd('Finding changed files');
return changedFiles;
}
function setupTrackingContext(configOrPath) {

@@ -132,7 +108,8 @@ return ({ tailwindDirectives , registerDependency })=>{

let contextDependencies = new Set(configDependencies);
// If there are no @tailwind rules, we don't consider this CSS file or it's dependencies
// to be dependencies of the context. Can reuse the context even if they change.
// We may want to think about `@layer` being part of this trigger too, but it's tough
// because it's impossible for a layer in one file to end up in the actual @tailwind rule
// in another file since independent sources are effectively isolated.
// If there are no @tailwind or @apply rules, we don't consider this CSS
// file or its dependencies to be dependencies of the context. Can reuse
// the context even if they change. We may want to think about `@layer`
// being part of this trigger too, but it's tough because it's impossible
// for a layer in one file to end up in the actual @tailwind rule in
// another file since independent sources are effectively isolated.
if (tailwindDirectives.size > 0) {

@@ -143,3 +120,3 @@ // Add current css file as a context dependencies.

for (let message of result.messages){
if (message.type === 'dependency') {
if (message.type === "dependency") {
contextDependencies.add(message.file);

@@ -149,6 +126,7 @@ }

}
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);
// If there are no @tailwind rules, we don't consider this CSS file or it's dependencies
// to be dependencies of the context. Can reuse the context even if they change.
// If there are no @tailwind or @apply rules, we don't consider this CSS file or it's
// dependencies to be dependencies of the context. Can reuse the context even if they change.
// We may want to think about `@layer` being part of this trigger too, but it's tough

@@ -158,20 +136,38 @@ // because it's impossible for a layer in one file to end up in the actual @tailwind rule

if (tailwindDirectives.size > 0) {
let fileModifiedMap = (0, _setupContextUtils).getFileModifiedMap(context);
// Add template paths as postcss dependencies.
for (let fileOrGlob of candidateFiles){
let dependency = (0, _parseDependency).default(fileOrGlob);
if (dependency) {
for (let contentPath of candidateFiles){
for (let dependency of (0, _parseDependency.default)(contentPath)){
registerDependency(dependency);
}
}
for (let changedContent of 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);
}
}
for (let file of configDependencies){
registerDependency({
type: 'dependency',
type: "dependency",
file
});
}
// "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;

@@ -178,0 +174,0 @@ };

@@ -5,16 +5,76 @@ "use strict";

});
exports.contextSourcesMap = exports.configContextMap = exports.env = exports.contextMap = void 0;
const env = {
TAILWIND_MODE: process.env.TAILWIND_MODE,
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
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 = typeof process !== "undefined" ? {
NODE_ENV: process.env.NODE_ENV,
DEBUG: process.env.DEBUG !== undefined,
TAILWIND_DISABLE_TOUCH: process.env.TAILWIND_DISABLE_TOUCH !== undefined,
TAILWIND_TOUCH_DIR: process.env.TAILWIND_TOUCH_DIR
DEBUG: resolveDebug(process.env.DEBUG)
} : {
NODE_ENV: "production",
DEBUG: false
};
exports.env = env;
const contextMap = new Map();
exports.contextMap = contextMap;
const configContextMap = new Map();
exports.configContextMap = configContextMap;
const contextSourcesMap = new Map();
exports.contextSourcesMap = contextSourcesMap;
const sourceHashMap = new Map();
const NOT_ON_DEMAND = new String("*");
const NONE = Symbol("__NONE__");
function resolveDebug(debug) {
if (debug === undefined) {
return false;
}
// Environment variables are strings, so convert to boolean
if (debug === "true" || debug === "1") {
return true;
}
if (debug === "false" || debug === "0") {
return false;
}
// Keep the debug convention into account:
// DEBUG=* -> This enables all debug modes
// DEBUG=projectA,projectB,projectC -> This enables debug for projectA, projectB and projectC
// DEBUG=projectA:* -> This enables all debug modes for projectA (if you have sub-types)
// DEBUG=projectA,-projectB -> This enables debug for projectA and explicitly disables it for projectB
if (debug === "*") {
return true;
}
let debuggers = debug.split(",").map((d)=>d.split(":")[0]);
// Ignoring tailwindcss
if (debuggers.includes("-tailwindcss")) {
return false;
}
// Including tailwindcss
if (debuggers.includes("tailwindcss")) {
return true;
}
return false;
}

@@ -5,5 +5,11 @@ "use strict";

});
exports.default = _default;
var _buildMediaQuery = _interopRequireDefault(require("../util/buildMediaQuery"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _normalizeScreens = require("../util/normalizeScreens");
const _buildMediaQuery = /*#__PURE__*/ _interop_require_default(require("../util/buildMediaQuery"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -15,12 +21,13 @@ default: obj

return function(css) {
css.walkAtRules('screen', (atRule)=>{
var ref, ref1;
const screen = atRule.params;
if (!((ref = theme.screens) === null || ref === void 0 ? void 0 : (ref1 = ref.hasOwnProperty) === null || ref1 === void 0 ? void 0 : ref1.call(ref, screen))) {
css.walkAtRules("screen", (atRule)=>{
let screen = atRule.params;
let screens = (0, _normalizeScreens.normalizeScreens)(theme.screens);
let screenDefinition = screens.find(({ name })=>name === screen);
if (!screenDefinition) {
throw atRule.error(`No \`${screen}\` screen found.`);
}
atRule.name = 'media';
atRule.params = (0, _buildMediaQuery).default(theme.screens[screen]);
atRule.name = "media";
atRule.params = (0, _buildMediaQuery.default)(screenDefinition);
});
};
}

@@ -5,14 +5,20 @@ "use strict";

});
exports.default = processTailwindFeatures;
var _normalizeTailwindDirectives = _interopRequireDefault(require("./lib/normalizeTailwindDirectives"));
var _expandTailwindAtRules = _interopRequireDefault(require("./lib/expandTailwindAtRules"));
var _expandApplyAtRules = _interopRequireDefault(require("./lib/expandApplyAtRules"));
var _evaluateTailwindFunctions = _interopRequireDefault(require("./lib/evaluateTailwindFunctions"));
var _substituteScreenAtRules = _interopRequireDefault(require("./lib/substituteScreenAtRules"));
var _resolveDefaultsAtRules = _interopRequireDefault(require("./lib/resolveDefaultsAtRules"));
var _collapseAdjacentRules = _interopRequireDefault(require("./lib/collapseAdjacentRules"));
var _detectNesting = _interopRequireDefault(require("./lib/detectNesting"));
var _setupContextUtils = require("./lib/setupContextUtils");
var _featureFlags = require("./featureFlags");
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return processTailwindFeatures;
}
});
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 _setupContextUtils = require("./lib/setupContextUtils");
const _featureFlags = require("./featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -23,9 +29,13 @@ default: obj

function processTailwindFeatures(setupContext) {
return function(root, result) {
let tailwindDirectives = (0, _normalizeTailwindDirectives).default(root);
return async function(root, result) {
let { tailwindDirectives , applyDirectives } = (0, _normalizeTailwindDirectives.default)(root);
// Partition apply rules that are found in the css
// itself.
(0, _partitionApplyAtRules.default)()(root, result);
let context = setupContext({
tailwindDirectives,
applyDirectives,
registerDependency (dependency) {
result.messages.push({
plugin: 'tailwindcss',
plugin: "tailwindcss",
parent: result.opts.from,

@@ -36,17 +46,20 @@ ...dependency

createContext (tailwindConfig, changedContent) {
return (0, _setupContextUtils).createContext(tailwindConfig, changedContent, root);
return (0, _setupContextUtils.createContext)(tailwindConfig, changedContent, root);
}
})(root, result);
if (context.tailwindConfig.separator === '-') {
if (context.tailwindConfig.separator === "-") {
throw new Error("The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead.");
}
(0, _featureFlags).issueFlagNotices(context.tailwindConfig);
(0, _detectNesting).default(context)(root, result);
(0, _expandTailwindAtRules).default(context)(root, result);
(0, _expandApplyAtRules).default(context)(root, result);
(0, _evaluateTailwindFunctions).default(context)(root, result);
(0, _substituteScreenAtRules).default(context)(root, result);
(0, _resolveDefaultsAtRules).default(context)(root, result);
(0, _collapseAdjacentRules).default(context)(root, result);
(0, _featureFlags.issueFlagNotices)(context.tailwindConfig);
await (0, _expandTailwindAtRules.default)(context)(root, result);
// Partition apply rules that are generated by
// addComponents, addUtilities and so on.
(0, _partitionApplyAtRules.default)()(root, result);
(0, _expandApplyAtRules.default)(context)(root, result);
(0, _evaluateTailwindFunctions.default)(context)(root, result);
(0, _substituteScreenAtRules.default)(context)(root, result);
(0, _resolveDefaultsAtRules.default)(context)(root, result);
(0, _collapseAdjacentRules.default)(context)(root, result);
(0, _collapseDuplicateDeclarations.default)(context)(root, result);
};
}

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = void 0;
var _log = _interopRequireDefault(require("../util/log"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _log = /*#__PURE__*/ _interop_require_default(require("../util/log"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -16,280 +21,302 @@ default: obj

`As of Tailwind CSS ${version}, \`${from}\` has been renamed to \`${to}\`.`,
'Update your configuration file to silence this warning.',
"Update your configuration file to silence this warning."
]);
}
var _default = {
inherit: 'inherit',
current: 'currentColor',
transparent: 'transparent',
black: '#000',
white: '#fff',
const _default = {
inherit: "inherit",
current: "currentColor",
transparent: "transparent",
black: "#000",
white: "#fff",
slate: {
50: '#f8fafc',
100: '#f1f5f9',
200: '#e2e8f0',
300: '#cbd5e1',
400: '#94a3b8',
500: '#64748b',
600: '#475569',
700: '#334155',
800: '#1e293b',
900: '#0f172a'
50: "#f8fafc",
100: "#f1f5f9",
200: "#e2e8f0",
300: "#cbd5e1",
400: "#94a3b8",
500: "#64748b",
600: "#475569",
700: "#334155",
800: "#1e293b",
900: "#0f172a",
950: "#020617"
},
gray: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827'
50: "#f9fafb",
100: "#f3f4f6",
200: "#e5e7eb",
300: "#d1d5db",
400: "#9ca3af",
500: "#6b7280",
600: "#4b5563",
700: "#374151",
800: "#1f2937",
900: "#111827",
950: "#030712"
},
zinc: {
50: '#fafafa',
100: '#f4f4f5',
200: '#e4e4e7',
300: '#d4d4d8',
400: '#a1a1aa',
500: '#71717a',
600: '#52525b',
700: '#3f3f46',
800: '#27272a',
900: '#18181b'
50: "#fafafa",
100: "#f4f4f5",
200: "#e4e4e7",
300: "#d4d4d8",
400: "#a1a1aa",
500: "#71717a",
600: "#52525b",
700: "#3f3f46",
800: "#27272a",
900: "#18181b",
950: "#09090b"
},
neutral: {
50: '#fafafa',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717'
50: "#fafafa",
100: "#f5f5f5",
200: "#e5e5e5",
300: "#d4d4d4",
400: "#a3a3a3",
500: "#737373",
600: "#525252",
700: "#404040",
800: "#262626",
900: "#171717",
950: "#0a0a0a"
},
stone: {
50: '#fafaf9',
100: '#f5f5f4',
200: '#e7e5e4',
300: '#d6d3d1',
400: '#a8a29e',
500: '#78716c',
600: '#57534e',
700: '#44403c',
800: '#292524',
900: '#1c1917'
50: "#fafaf9",
100: "#f5f5f4",
200: "#e7e5e4",
300: "#d6d3d1",
400: "#a8a29e",
500: "#78716c",
600: "#57534e",
700: "#44403c",
800: "#292524",
900: "#1c1917",
950: "#0c0a09"
},
red: {
50: '#fef2f2',
100: '#fee2e2',
200: '#fecaca',
300: '#fca5a5',
400: '#f87171',
500: '#ef4444',
600: '#dc2626',
700: '#b91c1c',
800: '#991b1b',
900: '#7f1d1d'
50: "#fef2f2",
100: "#fee2e2",
200: "#fecaca",
300: "#fca5a5",
400: "#f87171",
500: "#ef4444",
600: "#dc2626",
700: "#b91c1c",
800: "#991b1b",
900: "#7f1d1d",
950: "#450a0a"
},
orange: {
50: '#fff7ed',
100: '#ffedd5',
200: '#fed7aa',
300: '#fdba74',
400: '#fb923c',
500: '#f97316',
600: '#ea580c',
700: '#c2410c',
800: '#9a3412',
900: '#7c2d12'
50: "#fff7ed",
100: "#ffedd5",
200: "#fed7aa",
300: "#fdba74",
400: "#fb923c",
500: "#f97316",
600: "#ea580c",
700: "#c2410c",
800: "#9a3412",
900: "#7c2d12",
950: "#431407"
},
amber: {
50: '#fffbeb',
100: '#fef3c7',
200: '#fde68a',
300: '#fcd34d',
400: '#fbbf24',
500: '#f59e0b',
600: '#d97706',
700: '#b45309',
800: '#92400e',
900: '#78350f'
50: "#fffbeb",
100: "#fef3c7",
200: "#fde68a",
300: "#fcd34d",
400: "#fbbf24",
500: "#f59e0b",
600: "#d97706",
700: "#b45309",
800: "#92400e",
900: "#78350f",
950: "#451a03"
},
yellow: {
50: '#fefce8',
100: '#fef9c3',
200: '#fef08a',
300: '#fde047',
400: '#facc15',
500: '#eab308',
600: '#ca8a04',
700: '#a16207',
800: '#854d0e',
900: '#713f12'
50: "#fefce8",
100: "#fef9c3",
200: "#fef08a",
300: "#fde047",
400: "#facc15",
500: "#eab308",
600: "#ca8a04",
700: "#a16207",
800: "#854d0e",
900: "#713f12",
950: "#422006"
},
lime: {
50: '#f7fee7',
100: '#ecfccb',
200: '#d9f99d',
300: '#bef264',
400: '#a3e635',
500: '#84cc16',
600: '#65a30d',
700: '#4d7c0f',
800: '#3f6212',
900: '#365314'
50: "#f7fee7",
100: "#ecfccb",
200: "#d9f99d",
300: "#bef264",
400: "#a3e635",
500: "#84cc16",
600: "#65a30d",
700: "#4d7c0f",
800: "#3f6212",
900: "#365314",
950: "#1a2e05"
},
green: {
50: '#f0fdf4',
100: '#dcfce7',
200: '#bbf7d0',
300: '#86efac',
400: '#4ade80',
500: '#22c55e',
600: '#16a34a',
700: '#15803d',
800: '#166534',
900: '#14532d'
50: "#f0fdf4",
100: "#dcfce7",
200: "#bbf7d0",
300: "#86efac",
400: "#4ade80",
500: "#22c55e",
600: "#16a34a",
700: "#15803d",
800: "#166534",
900: "#14532d",
950: "#052e16"
},
emerald: {
50: '#ecfdf5',
100: '#d1fae5',
200: '#a7f3d0',
300: '#6ee7b7',
400: '#34d399',
500: '#10b981',
600: '#059669',
700: '#047857',
800: '#065f46',
900: '#064e3b'
50: "#ecfdf5",
100: "#d1fae5",
200: "#a7f3d0",
300: "#6ee7b7",
400: "#34d399",
500: "#10b981",
600: "#059669",
700: "#047857",
800: "#065f46",
900: "#064e3b",
950: "#022c22"
},
teal: {
50: '#f0fdfa',
100: '#ccfbf1',
200: '#99f6e4',
300: '#5eead4',
400: '#2dd4bf',
500: '#14b8a6',
600: '#0d9488',
700: '#0f766e',
800: '#115e59',
900: '#134e4a'
50: "#f0fdfa",
100: "#ccfbf1",
200: "#99f6e4",
300: "#5eead4",
400: "#2dd4bf",
500: "#14b8a6",
600: "#0d9488",
700: "#0f766e",
800: "#115e59",
900: "#134e4a",
950: "#042f2e"
},
cyan: {
50: '#ecfeff',
100: '#cffafe',
200: '#a5f3fc',
300: '#67e8f9',
400: '#22d3ee',
500: '#06b6d4',
600: '#0891b2',
700: '#0e7490',
800: '#155e75',
900: '#164e63'
50: "#ecfeff",
100: "#cffafe",
200: "#a5f3fc",
300: "#67e8f9",
400: "#22d3ee",
500: "#06b6d4",
600: "#0891b2",
700: "#0e7490",
800: "#155e75",
900: "#164e63",
950: "#083344"
},
sky: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e'
50: "#f0f9ff",
100: "#e0f2fe",
200: "#bae6fd",
300: "#7dd3fc",
400: "#38bdf8",
500: "#0ea5e9",
600: "#0284c7",
700: "#0369a1",
800: "#075985",
900: "#0c4a6e",
950: "#082f49"
},
blue: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6',
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a'
50: "#eff6ff",
100: "#dbeafe",
200: "#bfdbfe",
300: "#93c5fd",
400: "#60a5fa",
500: "#3b82f6",
600: "#2563eb",
700: "#1d4ed8",
800: "#1e40af",
900: "#1e3a8a",
950: "#172554"
},
indigo: {
50: '#eef2ff',
100: '#e0e7ff',
200: '#c7d2fe',
300: '#a5b4fc',
400: '#818cf8',
500: '#6366f1',
600: '#4f46e5',
700: '#4338ca',
800: '#3730a3',
900: '#312e81'
50: "#eef2ff",
100: "#e0e7ff",
200: "#c7d2fe",
300: "#a5b4fc",
400: "#818cf8",
500: "#6366f1",
600: "#4f46e5",
700: "#4338ca",
800: "#3730a3",
900: "#312e81",
950: "#1e1b4b"
},
violet: {
50: '#f5f3ff',
100: '#ede9fe',
200: '#ddd6fe',
300: '#c4b5fd',
400: '#a78bfa',
500: '#8b5cf6',
600: '#7c3aed',
700: '#6d28d9',
800: '#5b21b6',
900: '#4c1d95'
50: "#f5f3ff",
100: "#ede9fe",
200: "#ddd6fe",
300: "#c4b5fd",
400: "#a78bfa",
500: "#8b5cf6",
600: "#7c3aed",
700: "#6d28d9",
800: "#5b21b6",
900: "#4c1d95",
950: "#2e1065"
},
purple: {
50: '#faf5ff',
100: '#f3e8ff',
200: '#e9d5ff',
300: '#d8b4fe',
400: '#c084fc',
500: '#a855f7',
600: '#9333ea',
700: '#7e22ce',
800: '#6b21a8',
900: '#581c87'
50: "#faf5ff",
100: "#f3e8ff",
200: "#e9d5ff",
300: "#d8b4fe",
400: "#c084fc",
500: "#a855f7",
600: "#9333ea",
700: "#7e22ce",
800: "#6b21a8",
900: "#581c87",
950: "#3b0764"
},
fuchsia: {
50: '#fdf4ff',
100: '#fae8ff',
200: '#f5d0fe',
300: '#f0abfc',
400: '#e879f9',
500: '#d946ef',
600: '#c026d3',
700: '#a21caf',
800: '#86198f',
900: '#701a75'
50: "#fdf4ff",
100: "#fae8ff",
200: "#f5d0fe",
300: "#f0abfc",
400: "#e879f9",
500: "#d946ef",
600: "#c026d3",
700: "#a21caf",
800: "#86198f",
900: "#701a75",
950: "#4a044e"
},
pink: {
50: '#fdf2f8',
100: '#fce7f3',
200: '#fbcfe8',
300: '#f9a8d4',
400: '#f472b6',
500: '#ec4899',
600: '#db2777',
700: '#be185d',
800: '#9d174d',
900: '#831843'
50: "#fdf2f8",
100: "#fce7f3",
200: "#fbcfe8",
300: "#f9a8d4",
400: "#f472b6",
500: "#ec4899",
600: "#db2777",
700: "#be185d",
800: "#9d174d",
900: "#831843",
950: "#500724"
},
rose: {
50: '#fff1f2',
100: '#ffe4e6',
200: '#fecdd3',
300: '#fda4af',
400: '#fb7185',
500: '#f43f5e',
600: '#e11d48',
700: '#be123c',
800: '#9f1239',
900: '#881337'
50: "#fff1f2",
100: "#ffe4e6",
200: "#fecdd3",
300: "#fda4af",
400: "#fb7185",
500: "#f43f5e",
600: "#e11d48",
700: "#be123c",
800: "#9f1239",
900: "#881337",
950: "#4c0519"
},
get lightBlue () {
warn({
version: 'v2.2',
from: 'lightBlue',
to: 'sky'
version: "v2.2",
from: "lightBlue",
to: "sky"
});

@@ -300,5 +327,5 @@ return this.sky;

warn({
version: 'v3.0',
from: 'warmGray',
to: 'stone'
version: "v3.0",
from: "warmGray",
to: "stone"
});

@@ -309,5 +336,5 @@ return this.stone;

warn({
version: 'v3.0',
from: 'trueGray',
to: 'neutral'
version: "v3.0",
from: "trueGray",
to: "neutral"
});

@@ -318,5 +345,5 @@ return this.neutral;

warn({
version: 'v3.0',
from: 'coolGray',
to: 'gray'
version: "v3.0",
from: "coolGray",
to: "gray"
});

@@ -327,5 +354,5 @@ return this.gray;

warn({
version: 'v3.0',
from: 'blueGray',
to: 'slate'
version: "v3.0",
from: "blueGray",
to: "slate"
});

@@ -335,2 +362,1 @@ return this.slate;

};
exports.default = _default;

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = void 0;
var _createPlugin = _interopRequireDefault(require("../util/createPlugin"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _createPlugin = /*#__PURE__*/ _interop_require_default(require("../util/createPlugin"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -13,3 +18,2 @@ default: obj

}
var _default = _createPlugin.default;
exports.default = _default;
const _default = _createPlugin.default;

@@ -5,6 +5,11 @@ "use strict";

});
exports.default = void 0;
var _cloneDeep = require("../util/cloneDeep");
var _defaultConfigStub = _interopRequireDefault(require("../../stubs/defaultConfig.stub"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _cloneDeep = require("../util/cloneDeep");
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -14,3 +19,2 @@ default: obj

}
var _default = (0, _cloneDeep).cloneDeep(_defaultConfigStub.default);
exports.default = _default;
const _default = (0, _cloneDeep.cloneDeep)(_configfull.default);

@@ -5,6 +5,11 @@ "use strict";

});
exports.default = void 0;
var _cloneDeep = require("../util/cloneDeep");
var _defaultConfigStub = _interopRequireDefault(require("../../stubs/defaultConfig.stub"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
const _cloneDeep = require("../util/cloneDeep");
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -14,3 +19,2 @@ default: obj

}
var _default = (0, _cloneDeep).cloneDeep(_defaultConfigStub.default.theme);
exports.default = _default;
const _default = (0, _cloneDeep.cloneDeep)(_configfull.default.theme);

@@ -5,6 +5,11 @@ "use strict";

});
exports.default = resolveConfig;
var _resolveConfig = _interopRequireDefault(require("../util/resolveConfig"));
var _getAllConfigs = _interopRequireDefault(require("../util/getAllConfigs"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return resolveConfig;
}
});
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 : {

@@ -15,4 +20,4 @@ default: obj

function resolveConfig(...configs) {
let [, ...defaultConfigs] = (0, _getAllConfigs).default(configs[0]);
return (0, _resolveConfig).default([
let [, ...defaultConfigs] = (0, _getAllConfigs.default)(configs[0]);
return (0, _resolveConfig.default)([
...configs,

@@ -19,0 +24,0 @@ ...defaultConfigs

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = bigSign;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return bigSign;
}
});
function bigSign(bigIntValue) {
return (bigIntValue > 0n) - (bigIntValue < 0n);
}

@@ -5,28 +5,24 @@ "use strict";

});
exports.default = buildMediaQuery;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return buildMediaQuery;
}
});
function buildMediaQuery(screens) {
if (typeof screens === 'string') {
screens = {
min: screens
};
}
if (!Array.isArray(screens)) {
screens = [
screens
];
}
screens = Array.isArray(screens) ? screens : [
screens
];
return screens.map((screen)=>{
var ref;
if (screen === null || screen === void 0 ? void 0 : (ref = screen.hasOwnProperty) === null || ref === void 0 ? void 0 : ref.call(screen, 'raw')) {
return screen.raw;
}
return Object.entries(screen).map(([feature, value])=>{
var _feature;
feature = (_feature = ({
min: 'min-width',
max: 'max-width'
})[feature]) !== null && _feature !== void 0 ? _feature : feature;
return `(${feature}: ${value})`;
}).join(' and ');
}).join(', ');
let values = screen.values.map((screen)=>{
if (screen.raw !== undefined) {
return screen.raw;
}
return [
screen.min && `(min-width: ${screen.min})`,
screen.max && `(max-width: ${screen.max})`
].filter(Boolean).join(" and ");
});
return screen.not ? `not all and ${values}` : values;
}).join(", ");
}

@@ -5,16 +5,19 @@ "use strict";

});
exports.cloneDeep = cloneDeep;
Object.defineProperty(exports, "cloneDeep", {
enumerable: true,
get: function() {
return cloneDeep;
}
});
function cloneDeep(value) {
if (Array.isArray(value)) {
return value.map((child)=>cloneDeep(child)
);
return value.map((child)=>cloneDeep(child));
}
if (typeof value === 'object' && value !== null) {
if (typeof value === "object" && value !== null) {
return Object.fromEntries(Object.entries(value).map(([k, v])=>[
k,
cloneDeep(v)
]
));
]));
}
return value;
}

@@ -1,11 +0,38 @@

"use strict";
/**
* @param {import('postcss').Container[]} nodes
* @param {any} source
* @param {any} raws
* @returns {import('postcss').Container[]}
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = cloneNodes;
function cloneNodes(nodes, source) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return cloneNodes;
}
});
function cloneNodes(nodes, source = undefined, raws = undefined) {
return nodes.map((node)=>{
let cloned = node.clone();
if (raws !== undefined) {
cloned.raws.tailwind = {
...cloned.raws.tailwind,
...raws
};
}
if (source !== undefined) {
cloned.source = source;
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;
});
}

@@ -15,1 +42,14 @@ 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));
}
}

@@ -5,6 +5,18 @@ "use strict";

});
exports.parseColor = parseColor;
exports.formatColor = formatColor;
var _colorName = _interopRequireDefault(require("color-name"));
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
parseColor: function() {
return parseColor;
},
formatColor: function() {
return formatColor;
}
});
const _colorNames = /*#__PURE__*/ _interop_require_default(require("./colorNames"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -16,31 +28,33 @@ default: obj

let SHORT_HEX = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i;
let VALUE = `(?:\\d+|\\d*\\.\\d+)%?`;
let SEP = `(?:\\s*,\\s*|\\s+)`;
let ALPHA_SEP = `\\s*[,/]\\s*`;
let RGB_HSL = new RegExp(`^(rgb|hsl)a?\\(\\s*(${VALUE})${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`);
function parseColor(value) {
if (typeof value !== 'string') {
let VALUE = /(?:\d+|\d*\.\d+)%?/;
let SEP = /(?:\s*,\s*|\s+)/;
let ALPHA_SEP = /\s*[,/]\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 _match_, _match__toString;
if (typeof value !== "string") {
return null;
}
value = value.trim();
if (value === 'transparent') {
if (value === "transparent") {
return {
mode: 'rgb',
mode: "rgb",
color: [
'0',
'0',
'0'
"0",
"0",
"0"
],
alpha: '0'
alpha: "0"
};
}
if (value in _colorName.default) {
if (value in _colorNames.default) {
return {
mode: 'rgb',
color: _colorName.default[value].map((v)=>v.toString()
)
mode: "rgb",
color: _colorNames.default[value].map((v)=>v.toString())
};
}
let hex = value.replace(SHORT_HEX, (_, r, g, b, a)=>[
'#',
"#",
r,

@@ -52,8 +66,7 @@ r,

b,
a ? a + a : ''
].join('')
).match(HEX);
a ? a + a : ""
].join("")).match(HEX);
if (hex !== null) {
return {
mode: 'rgb',
mode: "rgb",
color: [

@@ -63,26 +76,45 @@ parseInt(hex[1], 16),

parseInt(hex[3], 16)
].map((v)=>v.toString()
),
].map((v)=>v.toString()),
alpha: hex[4] ? (parseInt(hex[4], 16) / 255).toString() : undefined
};
}
let match = value.match(RGB_HSL);
if (match !== null) {
var ref, ref1;
var _value_match;
let match = (_value_match = value.match(RGB)) !== null && _value_match !== void 0 ? _value_match : value.match(HSL);
if (match === null) {
return null;
}
let color = [
match[2],
match[3],
match[4]
].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: [
match[2],
match[3],
match[4]
].map((v)=>v.toString()
),
alpha: (ref = match[5]) === null || ref === void 0 ? void 0 : (ref1 = ref.toString) === null || ref1 === void 0 ? void 0 : ref1.call(ref)
color[0]
],
alpha: color[1]
};
}
return null;
if (!loose && color.length !== 3) {
return null;
}
if (color.length < 3 && !color.some((part)=>/^var\(.*?\)$/.test(part))) {
return null;
}
return {
mode: match[1],
color,
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_)
};
}
function formatColor({ mode , color , alpha }) {
let hasAlpha = alpha !== undefined;
return `${mode}(${color.join(' ')}${hasAlpha ? ` / ${alpha}` : ''})`;
if (mode === "rgba" || mode === "hsla") {
return `${mode}(${color.join(", ")}${hasAlpha ? `, ${alpha}` : ""})`;
}
return `${mode}(${color.join(" ")}${hasAlpha ? ` / ${alpha}` : ""})`;
}

@@ -5,3 +5,8 @@ "use strict";

});
exports.default = _default;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
function _default(pluginConfig, plugins) {

@@ -16,5 +21,5 @@ if (pluginConfig === undefined) {

return pluginConfig[pluginName] !== false;
}))),
})))
];
return pluginNames;
}

@@ -5,3 +5,8 @@ "use strict";

});
exports.default = void 0;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
function createPlugin(plugin, config) {

@@ -13,5 +18,3 @@ return {

}
createPlugin.withOptions = function(pluginFunction, configFunction = ()=>({
})
) {
createPlugin.withOptions = function(pluginFunction, configFunction = ()=>({})) {
const optionsFunction = function(options) {

@@ -31,3 +34,2 @@ return {

};
var _default = createPlugin;
exports.default = _default;
const _default = createPlugin;

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = createUtilityPlugin;
var _transformThemeValue = _interopRequireDefault(require("./transformThemeValue"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return createUtilityPlugin;
}
});
const _transformThemeValue = /*#__PURE__*/ _interop_require_default(require("./transformThemeValue"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -20,5 +25,4 @@ default: obj

]
], { filterDefault =false , ...options } = {
}) {
let transformValue = (0, _transformThemeValue).default(themeKey);
], { filterDefault =false , ...options } = {}) {
let transformValue = (0, _transformThemeValue.default)(themeKey);
return function({ matchUtilities , theme }) {

@@ -29,3 +33,3 @@ for (let utilityVariation of utilityVariations){

];
var ref;
var _theme;
matchUtilities(group.reduce((obj, [classPrefix, properties])=>{

@@ -43,12 +47,8 @@ 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)
});

@@ -55,0 +55,0 @@ }

@@ -5,69 +5,300 @@ "use strict";

});
exports.normalize = normalize;
exports.url = url;
exports.number = number;
exports.percentage = percentage;
exports.length = length;
exports.lineWidth = lineWidth;
exports.color = color;
exports.image = image;
exports.gradient = gradient;
exports.position = position;
exports.familyName = familyName;
exports.genericName = genericName;
exports.absoluteSize = absoluteSize;
exports.relativeSize = relativeSize;
var _color = require("./color");
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
normalize: function() {
return normalize;
},
normalizeAttributeSelectors: function() {
return normalizeAttributeSelectors;
},
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;
}
});
const _color = require("./color");
const _parseBoxShadowValue = require("./parseBoxShadowValue");
const _splitAtTopLevelOnly = require("./splitAtTopLevelOnly");
let cssFunctions = [
"min",
"max",
"clamp",
"calc"
];
// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
let COMMA = /,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
;
let UNDERSCORE = /_(?![^(]*\))/g // Underscore separator that is not located between brackets. E.g.: `rgba(255,_255,_255)_black` these don't count.
;
function normalize(value) {
function isCSSFunction(value) {
return cssFunctions.some((fn)=>new RegExp(`^${fn}\\(.*\\)`).test(value));
}
// 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
// - https://www.w3.org/TR/css-anchor-position-1
//
const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([
// Concrete properties
"scroll-timeline-name",
"timeline-scope",
"view-timeline-name",
"font-palette",
"anchor-name",
"anchor-scope",
"position-anchor",
"position-try-options",
// Shorthand properties
"scroll-timeline",
"animation-timeline",
"view-timeline",
"position-try"
]);
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(`
if (value.includes("url(")) {
return value.split(/(url\(.*?\))/g).filter(Boolean).map((part)=>{
if (/^url\(.*?\)$/.test(part)) {
return part;
}
return normalize(part, context, false);
}).join("");
}
// Convert `_` to ` `, except for escaped underscores `\_`
value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + ' '.repeat(fullMatch.length - 1)
).replace(/^_/g, ' ').replace(/\\_/g, '_');
value = value.replace(/([^\\])_+/g, (fullMatch, characterBefore)=>characterBefore + " ".repeat(fullMatch.length - 1)).replace(/^_/g, " ").replace(/\\_/g, "_");
// Remove leftover whitespace
value = value.trim();
// Keep raw strings if it starts with `url(`
if (value.startsWith('url(')) return value;
// Add spaces around operators inside calc() that do not follow an operator
// or '('.
return value.replace(/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ');
if (isRoot) {
value = value.trim();
}
value = normalizeMathOperatorSpacing(value);
return value;
}
function normalizeAttributeSelectors(value) {
// Wrap values in attribute selectors with quotes
if (value.includes("=")) {
value = value.replace(/(=.*)/g, (_fullMatch, match)=>{
if (match[1] === "'" || match[1] === '"') {
return match;
}
// Handle regex flags on unescaped values
if (match.length > 2) {
let trailingCharacter = match[match.length - 1];
if (match[match.length - 2] === " " && (trailingCharacter === "i" || trailingCharacter === "I" || trailingCharacter === "s" || trailingCharacter === "S")) {
return `="${match.slice(1, -2)}" ${match[match.length - 1]}`;
}
}
return `="${match.slice(1)}"`;
});
}
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",
"radial-gradient",
"linear-gradient",
"conic-gradient",
"repeating-radial-gradient",
"repeating-linear-gradient",
"repeating-conic-gradient",
"anchor-size"
];
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 (peek("[")) {
result += consumeUntil([
"]"
]);
} else if ([
"+",
"-",
"*",
"/"
].includes(char) && ![
"(",
"+",
"-",
"*",
"/",
","
].includes(lastChar())) {
result += ` ${char} `;
} else {
result += char;
}
}
// Simplify multiple spaces
return result.replace(/\s+/g, " ");
});
}
function url(value) {
return value.startsWith('url(');
return value.startsWith("url(");
}
function number(value) {
return !isNaN(Number(value));
return !isNaN(Number(value)) || isCSSFunction(value);
}
function percentage(value) {
return /%$/g.test(value) || /^calc\(.+?%\)/g.test(value);
return value.endsWith("%") && number(value.slice(0, -1)) || isCSSFunction(value);
}
// 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 = [
'cm',
'mm',
'Q',
'in',
'pc',
'pt',
'px',
'em',
'ex',
'ch',
'rem',
'lh',
'vw',
'vh',
'vmin',
'vmax',
"cm",
"mm",
"Q",
"in",
"pc",
"pt",
"px",
"em",
"ex",
"ch",
"rem",
"lh",
"rlh",
"vw",
"vh",
"vmin",
"vmax",
"vb",
"vi",
"svw",
"svh",
"lvw",
"lvh",
"dvw",
"dvh",
"cqw",
"cqh",
"cqi",
"cqb",
"cqmin",
"cqmax"
];
let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`;
let lengthUnitsPattern = `(?:${lengthUnits.join("|")})`;
function length(value) {
return new RegExp(`${lengthUnitsPattern}$`).test(value) || new RegExp(`^calc\\(.+?${lengthUnitsPattern}`).test(value);
return value === "0" || new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) || isCSSFunction(value);
}
let lineWidths = new Set([
'thin',
'medium',
'thick'
"thin",
"medium",
"thick"
]);

@@ -77,8 +308,19 @@ function lineWidth(value) {

}
function shadow(value) {
let parsedShadows = (0, _parseBoxShadowValue.parseBoxShadowValue)(normalize(value));
for (let parsedShadow of parsedShadows){
if (!parsedShadow.valid) {
return false;
}
}
return true;
}
function color(value) {
let colors = 0;
let result = value.split(UNDERSCORE).every((part)=>{
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
if ((0, _color).parseColor(part) !== null) return colors++, true;
if (part.startsWith("var(")) return true;
if ((0, _color.parseColor)(part, {
loose: true
}) !== null) return colors++, true;
return false;

@@ -91,12 +333,11 @@ });

let images = 0;
let result = value.split(COMMA).every((part)=>{
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
if (part.startsWith("var(")) return true;
if (url(part) || gradient(part) || [
'element(',
'image(',
'cross-fade(',
'image-set('
].some((fn)=>part.startsWith(fn)
)) {
"element(",
"image(",
"cross-fade(",
"image-set("
].some((fn)=>part.startsWith(fn))) {
images++;

@@ -111,7 +352,8 @@ return true;

let gradientTypes = new Set([
'linear-gradient',
'radial-gradient',
'repeating-linear-gradient',
'repeating-radial-gradient',
'conic-gradient',
"conic-gradient",
"linear-gradient",
"radial-gradient",
"repeating-conic-gradient",
"repeating-linear-gradient",
"repeating-radial-gradient"
]);

@@ -128,13 +370,13 @@ function gradient(value) {

let validPositions = new Set([
'center',
'top',
'right',
'bottom',
'left'
"center",
"top",
"right",
"bottom",
"left"
]);
function position(value) {
let positions = 0;
let result = value.split(UNDERSCORE).every((part)=>{
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, "_").every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
if (part.startsWith("var(")) return true;
if (validPositions.has(part) || length(part) || percentage(part)) {

@@ -151,7 +393,7 @@ positions++;

let fonts = 0;
let result = value.split(COMMA).every((part)=>{
let result = (0, _splitAtTopLevelOnly.splitAtTopLevelOnly)(value, ",").every((part)=>{
part = normalize(part);
if (part.startsWith('var(')) return true;
if (part.startsWith("var(")) return true;
// If it contains spaces, then it should be quoted
if (part.includes(' ')) {
if (part.includes(" ")) {
if (!/(['"])([^"']+)\1/g.test(part)) {

@@ -172,15 +414,15 @@ return false;

let genericNames = new Set([
'serif',
'sans-serif',
'monospace',
'cursive',
'fantasy',
'system-ui',
'ui-serif',
'ui-sans-serif',
'ui-monospace',
'ui-rounded',
'math',
'emoji',
'fangsong',
"serif",
"sans-serif",
"monospace",
"cursive",
"fantasy",
"system-ui",
"ui-serif",
"ui-sans-serif",
"ui-monospace",
"ui-rounded",
"math",
"emoji",
"fangsong"
]);

@@ -191,10 +433,10 @@ function genericName(value) {

let absoluteSizes = new Set([
'xx-small',
'x-small',
'small',
'medium',
'large',
'x-large',
'x-large',
'xxx-large',
"xx-small",
"x-small",
"small",
"medium",
"large",
"x-large",
"xx-large",
"xxx-large"
]);

@@ -205,4 +447,4 @@ function absoluteSize(value) {

let relativeSizes = new Set([
'larger',
'smaller'
"larger",
"smaller"
]);

@@ -209,0 +451,0 @@ function relativeSize(value) {

@@ -5,13 +5,24 @@ "use strict";

});
exports.defaults = defaults;
Object.defineProperty(exports, "defaults", {
enumerable: true,
get: function() {
return defaults;
}
});
function defaults(target, ...sources) {
for (let source of 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 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];
}
}
}
return target;
}

@@ -5,6 +5,11 @@ "use strict";

});
exports.default = escapeClassName;
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
var _escapeCommas = _interopRequireDefault(require("./escapeCommas"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return escapeClassName;
}
});
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 : {

@@ -15,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);
}

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = escapeCommas;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return escapeCommas;
}
});
function escapeCommas(className) {
return className.replace(/\\,/g, '\\2c ');
return className.replace(/\\,/g, "\\2c ");
}

@@ -5,16 +5,15 @@ "use strict";

});
exports.default = void 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])=>({
[color + (number === 'DEFAULT' ? '' : `-${number}`)]: hex
})
) : [
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return _default;
}
});
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])=>({
[color + (number === "DEFAULT" ? "" : `-${number}`)]: hex
})) : [
{
[`${color}`]: values
}
]
))
;
var _default = flattenColorPalette;
exports.default = _default;
]));
const _default = flattenColorPalette;

@@ -5,6 +5,11 @@ "use strict";

});
exports.default = getAllConfigs;
var _defaultConfigStubJs = _interopRequireDefault(require("../../stubs/defaultConfig.stub.js"));
var _featureFlags = require("../featureFlags");
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return getAllConfigs;
}
});
const _configfull = /*#__PURE__*/ _interop_require_default(require("../../stubs/config.full.js"));
const _featureFlags = require("../featureFlags");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -15,12 +20,28 @@ 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
]).slice().reverse().flatMap((preset)=>getAllConfigs(preset instanceof Function ? preset() : preset)
);
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));
const features = {
// Add experimental configs here...
respectDefaultRingColorOpacity: {
theme: {
ringColor: ({ theme })=>({
DEFAULT: "#3b82f67f",
...theme("colors")
})
}
},
disableColorOpacityUtilitiesByDefault: {
corePlugins: {
backgroundOpacity: false,
borderOpacity: false,
divideOpacity: false,
placeholderOpacity: false,
ringOpacity: false,
textOpacity: false
}
}
};
const experimentals = Object.keys(features).filter((feature)=>(0, _featureFlags).flagEnabled(config, feature)
).map((feature)=>features[feature]
);
const experimentals = Object.keys(features).filter((feature)=>(0, _featureFlags.flagEnabled)(config, feature)).map((feature)=>features[feature]);
return [

@@ -27,0 +48,0 @@ config,

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = hashConfig;
var _objectHash = _interopRequireDefault(require("object-hash"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return hashConfig;
}
});
const _objecthash = /*#__PURE__*/ _interop_require_default(require("object-hash"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -14,5 +19,5 @@ default: obj

function hashConfig(config) {
return (0, _objectHash).default(config, {
return (0, _objecthash.default)(config, {
ignoreUnknown: true
});
}

@@ -5,5 +5,10 @@ "use strict";

});
exports.default = isKeyframeRule;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return isKeyframeRule;
}
});
function isKeyframeRule(rule) {
return rule.parent && rule.parent.type === 'atrule' && /keyframes$/.test(rule.parent.name);
return rule.parent && rule.parent.type === "atrule" && /keyframes$/.test(rule.parent.name);
}

@@ -5,9 +5,14 @@ "use strict";

});
exports.default = isPlainObject;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return isPlainObject;
}
});
function isPlainObject(value) {
if (Object.prototype.toString.call(value) !== '[object Object]') {
if (Object.prototype.toString.call(value) !== "[object Object]") {
return false;
}
const prototype = Object.getPrototypeOf(value);
return prototype === null || prototype === Object.prototype;
return prototype === null || Object.getPrototypeOf(prototype) === null;
}

@@ -5,5 +5,18 @@ "use strict";

});
exports.default = void 0;
var _chalk = _interopRequireDefault(require("chalk"));
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
dim: function() {
return dim;
},
default: function() {
return _default;
}
});
const _picocolors = /*#__PURE__*/ _interop_require_default(require("picocolors"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -14,13 +27,15 @@ default: obj

let alreadyShown = new Set();
function log(chalk, messages, key) {
if (process.env.JEST_WORKER_ID !== undefined) return;
function log(type, messages, key) {
if (typeof process !== "undefined" && process.env.JEST_WORKER_ID) return;
if (key && alreadyShown.has(key)) return;
if (key) alreadyShown.add(key);
console.warn('');
messages.forEach((message)=>console.warn(chalk, '-', message)
);
console.warn("");
messages.forEach((message)=>console.warn(type, "-", message));
}
var _default = {
function dim(input) {
return _picocolors.default.dim(input);
}
const _default = {
info (key, messages) {
log(_chalk.default.bold.cyan('info'), ...Array.isArray(key) ? [
log(_picocolors.default.bold(_picocolors.default.cyan("info")), ...Array.isArray(key) ? [
key

@@ -33,3 +48,3 @@ ] : [

warn (key, messages) {
log(_chalk.default.bold.yellow('warn'), ...Array.isArray(key) ? [
log(_picocolors.default.bold(_picocolors.default.yellow("warn")), ...Array.isArray(key) ? [
key

@@ -42,3 +57,3 @@ ] : [

risk (key, messages) {
log(_chalk.default.bold.magenta('risk'), ...Array.isArray(key) ? [
log(_picocolors.default.bold(_picocolors.default.magenta("risk")), ...Array.isArray(key) ? [
key

@@ -51,2 +66,1 @@ ] : [

};
exports.default = _default;

@@ -5,7 +5,22 @@ "use strict";

});
exports.default = nameClass;
exports.formatClass = formatClass;
var _escapeClassName = _interopRequireDefault(require("./escapeClassName"));
var _escapeCommas = _interopRequireDefault(require("./escapeCommas"));
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
asClass: function() {
return asClass;
},
default: function() {
return nameClass;
},
formatClass: function() {
return formatClass;
}
});
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 : {

@@ -16,3 +31,3 @@ default: obj

function asClass(name) {
return (0, _escapeCommas).default(`.${(0, _escapeClassName).default(name)}`);
return (0, _escapeCommas.default)(`.${(0, _escapeClassName.default)(name)}`);
}

@@ -23,12 +38,15 @@ function nameClass(classPrefix, key) {

function formatClass(classPrefix, key) {
if (key === 'DEFAULT') {
if (key === "DEFAULT") {
return classPrefix;
}
if (key === '-' || key === '-DEFAULT') {
if (key === "-" || key === "-DEFAULT") {
return `-${classPrefix}`;
}
if (key.startsWith('-')) {
if (key.startsWith("-")) {
return `-${classPrefix}${key}`;
}
if (key.startsWith("/")) {
return `${classPrefix}${key}`;
}
return `${classPrefix}-${key}`;
}

@@ -5,16 +5,33 @@ "use strict";

});
exports.default = _default;
function _default(value) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return negateValue;
}
});
function negateValue(value) {
value = `${value}`;
if (value === '0') {
return '0';
if (value === "0") {
return "0";
}
// Flip sign of numbers
if (/^[+-]?(\d+|\d*\.\d+)(e[+-]?\d+)?(%|\w+)?$/.test(value)) {
return value.replace(/^[+-]?/, (sign)=>sign === '-' ? '' : '-'
);
return value.replace(/^[+-]?/, (sign)=>sign === "-" ? "" : "-");
}
if (value.includes('var(') || value.includes('calc(')) {
return `calc(${value} * -1)`;
// What functions we support negating numeric values for
// var() isn't inherently a numeric function but we support it anyway
// The trigonometric functions are omitted because you'll need to use calc(…) with them _anyway_
// to produce generally useful results and that will be covered already
let numericFunctions = [
"var",
"calc",
"min",
"max",
"clamp"
];
for (const fn of numericFunctions){
if (value.includes(`${fn}(`)) {
return `calc(${value} * -1)`;
}
}
}

@@ -5,9 +5,49 @@ "use strict";

});
exports.normalizeConfig = normalizeConfig;
var _log = _interopRequireDefault(require("./log"));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
Object.defineProperty(exports, "normalizeConfig", {
enumerable: true,
get: function() {
return normalizeConfig;
}
});
const _featureFlags = require("../featureFlags");
const _log = /*#__PURE__*/ _interop_require_wildcard(require("./log"));
function _getRequireWildcardCache(nodeInterop) {
if (typeof WeakMap !== "function") return null;
var cacheBabelInterop = new WeakMap();
var cacheNodeInterop = new WeakMap();
return (_getRequireWildcardCache = function(nodeInterop) {
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
})(nodeInterop);
}
function _interop_require_wildcard(obj, nodeInterop) {
if (!nodeInterop && obj && obj.__esModule) {
return obj;
}
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
return {
default: obj
};
}
var cache = _getRequireWildcardCache(nodeInterop);
if (cache && cache.has(obj)) {
return cache.get(obj);
}
var newObj = {};
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
for(var key in obj){
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
if (desc && (desc.get || desc.set)) {
Object.defineProperty(newObj, key, desc);
} else {
newObj[key] = obj[key];
}
}
}
newObj.default = obj;
if (cache) {
cache.set(obj, newObj);
}
return newObj;
}
function normalizeConfig(config) {

@@ -38,3 +78,3 @@ // Quick structure validation

// `config.content` should be an object or an array
if (!Array.isArray(config.content) && !(typeof config.content === 'object' && config.content !== null)) {
if (!Array.isArray(config.content) && !(typeof config.content === "object" && config.content !== null)) {
return false;

@@ -46,8 +86,8 @@ }

// `path` can be a string
if (typeof path === 'string') return true;
if (typeof path === "string") return true;
// `path` can be an object { raw: string, extension?: string }
// `raw` must be a string
if (typeof (path === null || path === void 0 ? void 0 : path.raw) !== 'string') return false;
if (typeof (path === null || path === void 0 ? void 0 : path.raw) !== "string") return false;
// `extension` (if provided) should also be a string
if ((path === null || path === void 0 ? void 0 : path.extension) && typeof (path === null || path === void 0 ? void 0 : path.extension) !== 'string') {
if ((path === null || path === void 0 ? void 0 : path.extension) && typeof (path === null || path === void 0 ? void 0 : path.extension) !== "string") {
return false;

@@ -59,10 +99,10 @@ }

// When `config.content` is an object
if (typeof config.content === 'object' && config.content !== null) {
// Only `files`, `extract` and `transform` can exist in `config.content`
if (typeof config.content === "object" && config.content !== null) {
// Only `files`, `relative`, `extract`, and `transform` can exist in `config.content`
if (Object.keys(config.content).some((key)=>![
'files',
'extract',
'transform'
].includes(key)
)) {
"files",
"relative",
"extract",
"transform"
].includes(key))) {
return false;

@@ -74,8 +114,8 @@ }

// `path` can be a string
if (typeof path === 'string') return true;
if (typeof path === "string") return true;
// `path` can be an object { raw: string, extension?: string }
// `raw` must be a string
if (typeof (path === null || path === void 0 ? void 0 : path.raw) !== 'string') return false;
if (typeof (path === null || path === void 0 ? void 0 : path.raw) !== "string") return false;
// `extension` (if provided) should also be a string
if ((path === null || path === void 0 ? void 0 : path.extension) && typeof (path === null || path === void 0 ? void 0 : path.extension) !== 'string') {
if ((path === null || path === void 0 ? void 0 : path.extension) && typeof (path === null || path === void 0 ? void 0 : path.extension) !== "string") {
return false;

@@ -88,21 +128,25 @@ }

// `config.content.extract` is optional, and can be a Function or a Record<String, Function>
if (typeof config.content.extract === 'object') {
if (typeof config.content.extract === "object") {
for (let value of Object.values(config.content.extract)){
if (typeof value !== 'function') {
if (typeof value !== "function") {
return false;
}
}
} else if (!(config.content.extract === undefined || typeof config.content.extract === 'function')) {
} else if (!(config.content.extract === undefined || typeof config.content.extract === "function")) {
return false;
}
// `config.content.transform` is optional, and can be a Function or a Record<String, Function>
if (typeof config.content.transform === 'object') {
if (typeof config.content.transform === "object") {
for (let value of Object.values(config.content.transform)){
if (typeof value !== 'function') {
if (typeof value !== "function") {
return false;
}
}
} else if (!(config.content.transform === undefined || typeof config.content.transform === 'function')) {
} else if (!(config.content.transform === undefined || typeof config.content.transform === "function")) {
return false;
}
// `config.content.relative` is optional and can be a boolean
if (typeof config.content.relative !== "boolean" && typeof config.content.relative !== "undefined") {
return false;
}
}

@@ -114,5 +158,6 @@ return true;

if (!valid) {
_log.default.warn('purge-deprecation', [
'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
'Update your configuration file to eliminate this warning.'
_log.default.warn("purge-deprecation", [
"The `purge`/`content` options have changed in Tailwind CSS v3.0.",
"Update your configuration file to eliminate this warning.",
"https://tailwindcss.com/docs/upgrade-guide#configure-content-sources"
]);

@@ -122,3 +167,3 @@ }

config.safelist = (()=>{
var ref;
var _purge_options;
let { content , purge , safelist } = config;

@@ -128,7 +173,40 @@ 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 [];
})();
// Normalize the `blocklist`
config.blocklist = (()=>{
let { blocklist } = config;
if (Array.isArray(blocklist)) {
if (blocklist.every((item)=>typeof item === "string")) {
return blocklist;
}
_log.default.warn("blocklist-invalid", [
"The `blocklist` option must be an array of strings.",
"https://tailwindcss.com/docs/content-configuration#discarding-classes"
]);
}
return [];
})();
// Normalize prefix option
if (typeof config.prefix === "function") {
_log.default.warn("prefix-function", [
"As of Tailwind CSS v3.0, `prefix` cannot be a function.",
"Update `prefix` in your configuration to be a string to eliminate this warning.",
"https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function"
]);
config.prefix = "";
} else {
var _config_prefix;
config.prefix = (_config_prefix = config.prefix) !== null && _config_prefix !== void 0 ? _config_prefix : "";
}
// Normalize the `content`
config.content = {
relative: (()=>{
let { content } = config;
if (content === null || content === void 0 ? void 0 : content.relative) {
return content.relative;
}
return (0, _featureFlags.flagEnabled)(config, "relativeContentPathsByDefault");
})(),
files: (()=>{

@@ -145,20 +223,18 @@ let { content , purge } = config;

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;
return {
};
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 {};
})();
let extractors = {
};
extractors.DEFAULT = (()=>{
var ref, ref46, ref47, ref48;
if ((ref = config.purge) === null || ref === void 0 ? void 0 : (ref46 = ref.options) === null || ref46 === void 0 ? void 0 : ref46.defaultExtractor) {
let extractors = {};
let 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 ((ref47 = config.content) === null || ref47 === void 0 ? void 0 : (ref48 = ref47.options) === null || ref48 === void 0 ? void 0 : ref48.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;

@@ -168,4 +244,7 @@ }

})();
if (defaultExtractor !== undefined) {
extractors.DEFAULT = defaultExtractor;
}
// Functions
if (typeof extract === 'function') {
if (typeof extract === "function") {
extractors.DEFAULT = extract;

@@ -178,3 +257,3 @@ } else if (Array.isArray(extract)) {

}
} else if (typeof extract === 'object' && extract !== null) {
} else if (typeof extract === "object" && extract !== null) {
Object.assign(extractors, extract);

@@ -186,16 +265,13 @@ }

let transform = (()=>{
var ref, ref61, ref62, ref63, ref64, ref65;
if ((ref = config.purge) === null || ref === void 0 ? void 0 : ref.transform) return config.purge.transform;
if ((ref61 = config.content) === null || ref61 === void 0 ? void 0 : ref61.transform) return config.content.transform;
if ((ref62 = config.purge) === null || ref62 === void 0 ? void 0 : (ref63 = ref62.transform) === null || ref63 === void 0 ? void 0 : ref63.DEFAULT) return config.purge.transform.DEFAULT;
if ((ref64 = config.content) === null || ref64 === void 0 ? void 0 : (ref65 = ref64.transform) === null || ref65 === void 0 ? void 0 : ref65.DEFAULT) return config.content.transform.DEFAULT;
return {
};
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 {};
})();
let transformers = {
};
if (typeof transform === 'function') {
let transformers = {};
if (typeof transform === "function") {
transformers.DEFAULT = transform;
}
if (typeof transform === 'object' && transform !== null) {
} else if (typeof transform === "object" && transform !== null) {
Object.assign(transformers, transform);

@@ -206,3 +282,14 @@ }

};
// Validate globs to prevent bogus globs.
// E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html`
for (let file of config.content.files){
if (typeof file === "string" && /{([^,]*?)}/g.test(file)) {
_log.default.warn("invalid-glob-braces", [
`The glob pattern ${(0, _log.dim)(file)} in your Tailwind CSS configuration is invalid.`,
`Update it to ${(0, _log.dim)(file.replace(/{([^,]*?)}/g, "$1"))} to silence this warning.`
]);
break;
}
}
return config;
}

@@ -5,36 +5,41 @@ "use strict";

});
exports.default = parseAnimationValue;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return parseAnimationValue;
}
});
const DIRECTIONS = new Set([
'normal',
'reverse',
'alternate',
'alternate-reverse'
"normal",
"reverse",
"alternate",
"alternate-reverse"
]);
const PLAY_STATES = new Set([
'running',
'paused'
"running",
"paused"
]);
const FILL_MODES = new Set([
'none',
'forwards',
'backwards',
'both'
"none",
"forwards",
"backwards",
"both"
]);
const ITERATION_COUNTS = new Set([
'infinite'
"infinite"
]);
const TIMINGS = new Set([
'linear',
'ease',
'ease-in',
'ease-out',
'ease-in-out',
'step-start',
'step-end',
"linear",
"ease",
"ease-in",
"ease-out",
"ease-in-out",
"step-start",
"step-end"
]);
const TIMING_FNS = [
'cubic-bezier',
'steps'
"cubic-bezier",
"steps"
];
const COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
const COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubic-bezier(a, b, c)` these don't count.
;

@@ -55,30 +60,29 @@ const SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.

for (let part of parts){
if (!seen.has('DIRECTIONS') && DIRECTIONS.has(part)) {
if (!seen.has("DIRECTIONS") && DIRECTIONS.has(part)) {
result.direction = part;
seen.add('DIRECTIONS');
} else if (!seen.has('PLAY_STATES') && PLAY_STATES.has(part)) {
seen.add("DIRECTIONS");
} else if (!seen.has("PLAY_STATES") && PLAY_STATES.has(part)) {
result.playState = part;
seen.add('PLAY_STATES');
} else if (!seen.has('FILL_MODES') && FILL_MODES.has(part)) {
seen.add("PLAY_STATES");
} else if (!seen.has("FILL_MODES") && FILL_MODES.has(part)) {
result.fillMode = part;
seen.add('FILL_MODES');
} else if (!seen.has('ITERATION_COUNTS') && (ITERATION_COUNTS.has(part) || DIGIT.test(part))) {
seen.add("FILL_MODES");
} else if (!seen.has("ITERATION_COUNTS") && (ITERATION_COUNTS.has(part) || DIGIT.test(part))) {
result.iterationCount = part;
seen.add('ITERATION_COUNTS');
} else if (!seen.has('TIMING_FUNCTION') && TIMINGS.has(part)) {
seen.add("ITERATION_COUNTS");
} else if (!seen.has("TIMING_FUNCTION") && TIMINGS.has(part)) {
result.timingFunction = part;
seen.add('TIMING_FUNCTION');
} else if (!seen.has('TIMING_FUNCTION') && TIMING_FNS.some((f)=>part.startsWith(`${f}(`)
)) {
seen.add("TIMING_FUNCTION");
} else if (!seen.has("TIMING_FUNCTION") && TIMING_FNS.some((f)=>part.startsWith(`${f}(`))) {
result.timingFunction = part;
seen.add('TIMING_FUNCTION');
} else if (!seen.has('DURATION') && TIME.test(part)) {
seen.add("TIMING_FUNCTION");
} else if (!seen.has("DURATION") && TIME.test(part)) {
result.duration = part;
seen.add('DURATION');
} else if (!seen.has('DELAY') && TIME.test(part)) {
seen.add("DURATION");
} else if (!seen.has("DELAY") && TIME.test(part)) {
result.delay = part;
seen.add('DELAY');
} else if (!seen.has('NAME')) {
seen.add("DELAY");
} else if (!seen.has("NAME")) {
result.name = part;
seen.add('NAME');
seen.add("NAME");
} else {

@@ -85,0 +89,0 @@ if (!result.unknown) result.unknown = [];

@@ -1,63 +0,47 @@

"use strict";
// @ts-check
/**
* @typedef {{type: 'dependency', file: string} | {type: 'dir-dependency', dir: string, glob: string}} Dependency
*/ /**
*
* @param {import('../lib/content.js').ContentPath} contentPath
* @returns {Dependency[]}
*/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = parseDependency;
var _isGlob = _interopRequireDefault(require("is-glob"));
var _globParent = _interopRequireDefault(require("glob-parent"));
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
// Based on `glob-base`
// https://github.com/micromatch/glob-base/blob/master/index.js
function parseGlob(pattern) {
let glob = pattern;
let base = (0, _globParent).default(pattern);
if (base !== '.') {
glob = pattern.substr(base.length);
if (glob.charAt(0) === '/') {
glob = glob.substr(1);
}
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return parseDependency;
}
if (glob.substr(0, 2) === './') {
glob = glob.substr(2);
});
function parseDependency(contentPath) {
if (contentPath.ignore) {
return [];
}
if (glob.charAt(0) === '/') {
glob = glob.substr(1);
if (!contentPath.glob) {
return [
{
type: "dependency",
file: contentPath.base
}
];
}
return {
base,
glob
};
}
function parseDependency(normalizedFileOrGlob) {
if (normalizedFileOrGlob.startsWith('!')) {
return null;
if (process.env.ROLLUP_WATCH === "true") {
// rollup-plugin-postcss does not support dir-dependency messages
// but directories can be watched in the same way as files
return [
{
type: "dependency",
file: contentPath.base
}
];
}
let message;
if ((0, _isGlob).default(normalizedFileOrGlob)) {
let { base , glob } = parseGlob(normalizedFileOrGlob);
message = {
type: 'dir-dependency',
dir: _path.default.resolve(base),
glob
};
} else {
message = {
type: 'dependency',
file: _path.default.resolve(normalizedFileOrGlob)
};
}
// rollup-plugin-postcss does not support dir-dependency messages
// but directories can be watched in the same way as files
if (message.type === 'dir-dependency' && process.env.ROLLUP_WATCH === 'true') {
message = {
type: 'dependency',
file: message.dir
};
}
return message;
return [
{
type: "dir-dependency",
dir: contentPath.base,
glob: contentPath.glob
}
];
}

@@ -5,7 +5,12 @@ "use strict";

});
exports.default = parseObjectStyles;
var _postcss = _interopRequireDefault(require("postcss"));
var _postcssNested = _interopRequireDefault(require("postcss-nested"));
var _postcssJs = _interopRequireDefault(require("postcss-js"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return parseObjectStyles;
}
});
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 : {

@@ -22,12 +27,12 @@ default: obj

return styles.flatMap((style)=>{
return (0, _postcss).default([
(0, _postcssNested).default({
return (0, _postcss.default)([
(0, _postcssnested.default)({
bubble: [
'screen'
"screen"
]
}),
})
]).process(style, {
parser: _postcssJs.default
parser: _postcssjs.default
}).root.nodes;
});
}

@@ -5,19 +5,41 @@ "use strict";

});
exports.applyStateToMarker = applyStateToMarker;
exports.updateAllClasses = updateAllClasses;
exports.updateLastClasses = updateLastClasses;
exports.transformAllSelectors = transformAllSelectors;
exports.transformAllClasses = transformAllClasses;
exports.transformLastClasses = transformLastClasses;
exports.asValue = asValue;
exports.asColor = asColor;
exports.asLookupValue = asLookupValue;
exports.coerceValue = coerceValue;
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
var _escapeCommas = _interopRequireDefault(require("./escapeCommas"));
var _withAlphaVariable = require("./withAlphaVariable");
var _isKeyframeRule = _interopRequireDefault(require("./isKeyframeRule"));
var _dataTypes = require("./dataTypes");
var _negateValue = _interopRequireDefault(require("./negateValue"));
function _interopRequireDefault(obj) {
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
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 _escapeCommas = /*#__PURE__*/ _interop_require_default(require("./escapeCommas"));
const _withAlphaVariable = require("./withAlphaVariable");
const _dataTypes = require("./dataTypes");
const _negateValue = /*#__PURE__*/ _interop_require_default(require("./negateValue"));
const _validateFormalSyntax = require("./validateFormalSyntax");
const _featureFlags = require("../featureFlags.js");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -27,140 +49,10 @@ default: obj

}
function applyStateToMarker(selector, marker, state, join) {
let markerIdx = selector.search(new RegExp(`${marker}[:[]`));
if (markerIdx === -1) {
return join(marker + state, selector);
}
let markerSelector = selector.slice(markerIdx, selector.indexOf(' ', markerIdx));
return join(marker + state + markerSelector.slice(markerIdx + marker.length), selector.replace(markerSelector, ''));
}
function updateAllClasses(selectors, updateClass) {
let parser = (0, _postcssSelectorParser).default((selectors)=>{
selectors.walkClasses((sel)=>{
let updatedClass = updateClass(sel.value, {
withAttr (className, attr) {
sel.parent.insertAfter(sel, _postcssSelectorParser.default.attribute({
attribute: attr.slice(1, -1)
}));
return className;
},
withPseudo (className, pseudo) {
sel.parent.insertAfter(sel, _postcssSelectorParser.default.pseudo({
value: pseudo
}));
return className;
}
});
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 updateLastClasses(selectors, updateClass) {
let parser = (0, _postcssSelectorParser).default((selectors)=>{
selectors.each((sel)=>{
let lastClass = sel.filter(({ type })=>type === 'class'
).pop();
if (lastClass === undefined) {
return;
}
let updatedClass = updateClass(lastClass.value, {
withPseudo (className, pseudo) {
lastClass.parent.insertAfter(lastClass, _postcssSelectorParser.default.pseudo({
value: `${pseudo}`
}));
return className;
}
});
lastClass.value = updatedClass;
if (lastClass.raws && lastClass.raws.value) {
lastClass.raws.value = (0, _escapeCommas).default(lastClass.raws.value);
}
});
});
let result = parser.processSync(selectors);
return result;
}
function splitByNotEscapedCommas(str) {
let chunks = [];
let currentChunk = '';
for(let i = 0; i < str.length; i++){
if (str[i] === ',' && str[i - 1] !== '\\') {
chunks.push(currentChunk);
currentChunk = '';
} else {
currentChunk += str[i];
}
}
chunks.push(currentChunk);
return chunks;
}
function transformAllSelectors(transformSelector, { wrap , withRule } = {
}) {
return ({ container })=>{
container.walkRules((rule)=>{
if ((0, _isKeyframeRule).default(rule)) {
return rule;
}
let transformed = splitByNotEscapedCommas(rule.selector).map(transformSelector).join(',');
rule.selector = transformed;
if (withRule) {
withRule(rule);
}
return rule;
});
if (wrap) {
let wrapper = wrap();
let nodes = container.nodes;
container.removeAll();
wrapper.append(nodes);
container.append(wrapper);
}
};
}
function transformAllClasses(transformClass, { wrap , withRule } = {
}) {
return ({ container })=>{
container.walkRules((rule)=>{
let selector = rule.selector;
let variantSelector = updateAllClasses(selector, transformClass);
rule.selector = variantSelector;
if (withRule) {
withRule(rule);
}
return rule;
});
if (wrap) {
let wrapper = wrap();
let nodes = container.nodes;
container.removeAll();
wrapper.append(nodes);
container.append(wrapper);
}
};
}
function transformLastClasses(transformClass, { wrap , withRule } = {
}) {
return ({ container })=>{
container.walkRules((rule)=>{
let selector = rule.selector;
let variantSelector = updateLastClasses(selector, transformClass);
rule.selector = variantSelector;
if (withRule) {
withRule(rule);
}
return rule;
});
if (wrap) {
let wrapper = wrap();
let nodes = container.nodes;
container.removeAll();
wrapper.append(nodes);
container.append(wrapper);
}
};
}
function resolveArbitraryValue(modifier, validate) {

@@ -174,9 +66,8 @@ if (!isArbitraryValue(modifier)) {

}
return (0, _dataTypes).normalize(value);
return (0, _dataTypes.normalize)(value);
}
function asNegativeValue(modifier, lookup = {
}, validate) {
function asNegativeValue(modifier, lookup = {}, validate) {
let positiveValue = lookup[modifier];
if (positiveValue !== undefined) {
return (0, _negateValue).default(positiveValue);
return (0, _negateValue.default)(positiveValue);
}

@@ -188,15 +79,12 @@ if (isArbitraryValue(modifier)) {

}
return (0, _negateValue).default(resolved);
return (0, _negateValue.default)(resolved);
}
}
function asValue(modifier, options = {
}, { validate =()=>true
} = {
}) {
var ref;
let value = (ref = options.values) === null || ref === void 0 ? void 0 : ref[modifier];
function asValue(modifier, options = {}, { validate =()=>true } = {}) {
var _options_values;
let value = (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier];
if (value !== undefined) {
return value;
}
if (options.supportsNegativeValues && modifier.startsWith('-')) {
if (options.supportsNegativeValues && modifier.startsWith("-")) {
return asNegativeValue(modifier.slice(1), options.values, validate);

@@ -207,11 +95,35 @@ }

function isArbitraryValue(input) {
return input.startsWith('[') && input.endsWith(']');
return input.startsWith("[") && input.endsWith("]");
}
function splitAlpha(modifier) {
let slashIdx = modifier.lastIndexOf('/');
function splitUtilityModifier(modifier) {
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) {
return [
modifier
modifier,
undefined
];
}
let arbitrary = isArbitraryValue(modifier);
// The modifier could be of the form `[foo]/[bar]`
// We want to handle this case properly
// without affecting `[foo/bar]`
if (arbitrary && !modifier.includes("]/[")) {
return [
modifier,
undefined
];
}
return [

@@ -222,26 +134,36 @@ modifier.slice(0, slashIdx),

}
function asColor(modifier, options = {
}, { tailwindConfig ={
} } = {
}) {
var ref7;
if (((ref7 = options.values) === null || ref7 === void 0 ? void 0 : ref7[modifier]) !== undefined) {
var ref;
return (ref = options.values) === null || ref === void 0 ? void 0 : ref[modifier];
function parseColorFormat(value) {
if (typeof value === "string" && value.includes("<alpha-value>")) {
let oldValue = value;
return ({ opacityValue =1 })=>oldValue.replace(/<alpha-value>/g, opacityValue);
}
let [color, alpha] = splitAlpha(modifier);
return value;
}
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(modifier);
if (alpha !== undefined) {
var ref, ref1, ref2;
var ref3;
let normalizedColor = (ref3 = (ref = options.values) === null || ref === void 0 ? void 0 : ref[color]) !== null && ref3 !== void 0 ? ref3 : 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) {
return undefined;
}
normalizedColor = parseColorFormat(normalizedColor);
if (isArbitraryValue(alpha)) {
return (0, _withAlphaVariable).withAlphaValue(normalizedColor, alpha.slice(1, -1));
return (0, _withAlphaVariable.withAlphaValue)(normalizedColor, unwrapArbitraryModifier(alpha));
}
if (((ref1 = tailwindConfig.theme) === null || ref1 === void 0 ? void 0 : (ref2 = ref1.opacity) === null || ref2 === void 0 ? void 0 : ref2[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;
}
return (0, _withAlphaVariable).withAlphaValue(normalizedColor, tailwindConfig.theme.opacity[alpha]);
return (0, _withAlphaVariable.withAlphaValue)(normalizedColor, tailwindConfig.theme.opacity[alpha]);
}

@@ -252,6 +174,5 @@ return asValue(modifier, options, {

}
function asLookupValue(modifier, options = {
}) {
var ref;
return (ref = options.values) === null || ref === void 0 ? void 0 : ref[modifier];
function asLookupValue(modifier, options = {}) {
var _options_values;
return (_options_values = options.values) === null || _options_values === void 0 ? void 0 : _options_values[modifier];
}

@@ -274,8 +195,10 @@ function guess(validate) {

lookup: asLookupValue,
'generic-name': guess(_dataTypes.genericName),
'family-name': guess(_dataTypes.familyName),
"generic-name": guess(_dataTypes.genericName),
"family-name": guess(_dataTypes.familyName),
number: guess(_dataTypes.number),
'line-width': guess(_dataTypes.lineWidth),
'absolute-size': guess(_dataTypes.absoluteSize),
'relative-size': guess(_dataTypes.relativeSize)
"line-width": guess(_dataTypes.lineWidth),
"absolute-size": guess(_dataTypes.absoluteSize),
"relative-size": guess(_dataTypes.relativeSize),
shadow: guess(_dataTypes.shadow),
size: guess(_validateFormalSyntax.backgroundSize)
};

@@ -295,5 +218,26 @@ let supportedTypes = Object.keys(typeMap);

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)) {
let [explicitType, value] = splitAtFirst(modifier.slice(1, -1), ':');
if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
let arbitraryValue = modifier.slice(1, -1);
let [explicitType, value] = splitAtFirst(arbitraryValue, ":");
// It could be that this resolves to `url(https` which is not a valid
// identifier. We currently only support "simple" words with dashes or
// underscores. E.g.: family-name
if (!/^[\w-_]+$/g.test(explicitType)) {
value = arbitraryValue;
} else if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
return [];

@@ -304,17 +248,52 @@ }

asValue(`[${value}]`, options),
explicitType
explicitType,
null
];
}
}
let matches = getMatchingTypes(types, modifier, options, tailwindConfig);
// Find first matching type
for (let type of [].concat(types)){
for (let match of matches){
return match;
}
return [];
}
function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
let modifiersEnabled = (0, _featureFlags.flagEnabled)(tailwindConfig, "generalizedModifiers");
let [modifier, utilityModifier] = splitUtilityModifier(rawModifier);
let canUseUtilityModifier = modifiersEnabled && options.modifiers != null && (options.modifiers === "any" || typeof options.modifiers === "object" && (utilityModifier && isArbitraryValue(utilityModifier) || utilityModifier in options.modifiers));
if (!canUseUtilityModifier) {
modifier = rawModifier;
utilityModifier = undefined;
}
if (utilityModifier !== undefined && modifier === "") {
modifier = "DEFAULT";
}
// Check the full value first
// TODO: Move to asValue… somehow
if (utilityModifier !== undefined) {
if (typeof options.modifiers === "object") {
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 = unwrapArbitraryModifier(utilityModifier);
}
}
}
for (let { type } of types !== null && types !== void 0 ? types : []){
let result = typeMap[type](modifier, options, {
tailwindConfig
});
if (result) return [
if (result === undefined) {
continue;
}
yield [
result,
type
type,
utilityModifier !== null && utilityModifier !== void 0 ? utilityModifier : null
];
}
return [];
}

@@ -5,6 +5,21 @@ "use strict";

});
exports.default = _default;
var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));
var _tap = require("./tap");
function _interopRequireDefault(obj) {
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: function() {
return _default;
}
});
const _postcssselectorparser = /*#__PURE__*/ _interop_require_default(require("postcss-selector-parser"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -14,12 +29,13 @@ default: obj

}
function _default(prefix, selector) {
const getPrefix = typeof prefix === 'function' ? prefix : ()=>prefix === undefined ? '' : prefix
;
return (0, _postcssSelectorParser).default((selectors)=>{
selectors.walkClasses((classSelector)=>{
(0, _tap).tap(classSelector.value, (baseClass)=>{
classSelector.value = `${getPrefix('.' + baseClass)}${baseClass}`;
});
});
}).processSync(selector);
function _default(prefix, selector, prependNegative = false) {
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;
}

@@ -5,12 +5,21 @@ "use strict";

});
exports.default = resolveConfig;
var _negateValue = _interopRequireDefault(require("./negateValue"));
var _corePluginList = _interopRequireDefault(require("../corePluginList"));
var _configurePlugins = _interopRequireDefault(require("./configurePlugins"));
var _defaultConfigStub = _interopRequireDefault(require("../../stubs/defaultConfig.stub"));
var _colors = _interopRequireDefault(require("../public/colors"));
var _defaults = require("./defaults");
var _toPath = require("./toPath");
var _normalizeConfig = require("./normalizeConfig");
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return resolveConfig;
}
});
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__*/ _interop_require_default(require("./isPlainObject"));
const _cloneDeep = require("./cloneDeep");
const _pluginUtils = require("./pluginUtils");
const _withAlphaVariable = require("./withAlphaVariable");
const _toColorValue = /*#__PURE__*/ _interop_require_default(require("./toColorValue"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -21,7 +30,4 @@ default: obj

function isFunction(input) {
return typeof input === 'function';
return typeof input === "function";
}
function isObject(input) {
return typeof input === 'object' && input !== null;
}
function mergeWith(target, ...sources) {

@@ -33,4 +39,4 @@ let customizer = sources.pop();

if (merged === undefined) {
if (isObject(target[k]) && isObject(source[k])) {
target[k] = mergeWith(target[k], source[k], customizer);
if ((0, _isPlainObject.default)(target[k]) && (0, _isPlainObject.default)(source[k])) {
target[k] = mergeWith({}, target[k], source[k], customizer);
} else {

@@ -50,5 +56,4 @@ target[k] = source[k];

// TODO: Log that this function isn't really needed anymore?
return Object.keys(scale).filter((key)=>scale[key] !== '0'
).reduce((negativeScale, key)=>{
let negativeValue = (0, _negateValue).default(scale[key]);
return Object.keys(scale).filter((key)=>scale[key] !== "0").reduce((negativeScale, key)=>{
let negativeValue = (0, _negateValue.default)(scale[key]);
if (negativeValue !== undefined) {

@@ -58,13 +63,9 @@ negativeScale[`-${key}`] = negativeValue;

return negativeScale;
}, {
});
}, {});
},
breakpoints (screens) {
return Object.keys(screens).filter((key)=>typeof screens[key] === 'string'
).reduce((breakpoints, key)=>({
return Object.keys(screens).filter((key)=>typeof screens[key] === "string").reduce((breakpoints, key)=>({
...breakpoints,
[`screen-${key}`]: screens[key]
})
, {
});
}), {});
}

@@ -94,10 +95,7 @@ };

});
}, {
});
}, {});
}
function mergeThemes(themes) {
return {
...themes.reduce((merged, theme)=>(0, _defaults).defaults(merged, theme)
, {
}),
...themes.reduce((merged, theme)=>(0, _defaults.defaults)(merged, theme), {}),
// In order to resolve n config objects, we combine all of their `extend` properties

@@ -110,7 +108,7 @@ // into arrays instead of objects so they aren't overridden.

// When we have an array of objects, we do want to merge it
if (Array.isArray(merged) && isObject(merged[0])) {
if (Array.isArray(merged) && (0, _isPlainObject.default)(merged[0])) {
return merged.concat(value);
}
// When the incoming value is an array, and the existing config is an object, prepend the existing object
if (Array.isArray(value) && isObject(value[0]) && isObject(merged)) {
if (Array.isArray(value) && (0, _isPlainObject.default)(value[0]) && (0, _isPlainObject.default)(merged)) {
return [

@@ -132,36 +130,64 @@ merged,

if (!isFunction(themeValue) && !extensions.some(isFunction)) {
return mergeWith({
}, themeValue, ...extensions, mergeExtensionCustomizer);
return mergeWith({}, themeValue, ...extensions, mergeExtensionCustomizer);
}
return (resolveThemePath, utils)=>mergeWith({
}, ...[
return (resolveThemePath, utils)=>mergeWith({}, ...[
themeValue,
...extensions
].map((e)=>value(e, resolveThemePath, utils)
), mergeExtensionCustomizer)
;
].map((e)=>value(e, resolveThemePath, utils)), mergeExtensionCustomizer);
});
}
/**
*
* @param {string} key
* @return {Iterable<string[] & {alpha: string | undefined}>}
*/ function* toPaths(key) {
let path = (0, _toPath.toPath)(key);
if (path.length === 0) {
return;
}
yield path;
if (Array.isArray(key)) {
return;
}
let pattern = /^(.*?)\s*\/\s*([^/]+)$/;
let matches = key.match(pattern);
if (matches !== null) {
let [, prefix, alpha] = matches;
let newPath = (0, _toPath.toPath)(prefix);
newPath.alpha = alpha;
yield newPath;
}
}
function resolveFunctionKeys(object) {
// theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5]
const resolvePath = (key, defaultValue)=>{
const path = (0, _toPath).toPath(key);
let index = 0;
let val = object;
while(val !== undefined && val !== null && index < path.length){
val = val[path[index++]];
val = isFunction(val) ? val(resolvePath, configUtils) : val;
for (const path of toPaths(key)){
let index = 0;
let val = object;
while(val !== undefined && val !== null && index < path.length){
val = val[path[index++]];
let shouldResolveAsFn = isFunction(val) && (path.alpha === undefined || index <= path.length - 1);
val = shouldResolveAsFn ? val(resolvePath, configUtils) : val;
}
if (val !== undefined) {
if (path.alpha !== undefined) {
let normalized = (0, _pluginUtils.parseColorFormat)(val);
return (0, _withAlphaVariable.withAlphaValue)(normalized, path.alpha, (0, _toColorValue.default)(normalized));
}
if ((0, _isPlainObject.default)(val)) {
return (0, _cloneDeep.cloneDeep)(val);
}
return val;
}
}
return val === undefined ? defaultValue : val;
return defaultValue;
};
resolvePath.theme = resolvePath;
for(let key in configUtils){
resolvePath[key] = configUtils[key];
}
Object.assign(resolvePath, {
theme: resolvePath,
...configUtils
});
return Object.keys(object).reduce((resolved, key)=>{
return {
...resolved,
[key]: isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key]
};
}, {
});
resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key];
return resolved;
}, {});
}

@@ -175,4 +201,4 @@ function extractPluginConfigs(configs) {

];
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) {

@@ -185,8 +211,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 : {}
])

@@ -207,3 +232,3 @@ ];

}
return (0, _configurePlugins).default(corePluginConfig, resolved);
return (0, _configurePlugins.default)(corePluginConfig, resolved);
}, _corePluginList.default);

@@ -227,20 +252,17 @@ return result;

{
prefix: '',
prefix: "",
important: false,
separator: ':',
variantOrder: _defaultConfigStub.default.variantOrder
},
separator: ":"
}
];
var ref, ref1;
return (0, _normalizeConfig).normalizeConfig((0, _defaults).defaults({
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
)),
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,6 +5,19 @@ "use strict";

});
exports.default = resolveConfigPath;
var _fs = _interopRequireDefault(require("fs"));
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(obj) {
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__*/ _interop_require_default(require("fs"));
const _path = /*#__PURE__*/ _interop_require_default(require("path"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {

@@ -14,4 +27,12 @@ default: obj

}
const defaultConfigFiles = [
"./tailwind.config.js",
"./tailwind.config.cjs",
"./tailwind.config.mjs",
"./tailwind.config.ts",
"./tailwind.config.cts",
"./tailwind.config.mts"
];
function isObject(value) {
return typeof value === 'object' && value !== null;
return typeof value === "object" && value !== null;
}

@@ -22,3 +43,3 @@ function isEmpty(obj) {

function isString(value) {
return typeof value === 'string' || value instanceof String;
return typeof value === "string" || value instanceof String;
}

@@ -43,6 +64,6 @@ function resolveConfigPath(pathOrConfig) {

// require('tailwindcss')
for (const configFile of [
'./tailwind.config.js',
'./tailwind.config.cjs'
]){
return resolveDefaultConfigPath();
}
function resolveDefaultConfigPath() {
for (const configFile of defaultConfigFiles){
try {

@@ -52,6 +73,5 @@ const configPath = _path.default.resolve(configFile);

return configPath;
} catch (err) {
}
} catch (err) {}
}
return null;
}

@@ -5,6 +5,11 @@ "use strict";

});
exports.default = responsive;
var _postcss = _interopRequireDefault(require("postcss"));
var _cloneNodes = _interopRequireDefault(require("./cloneNodes"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return responsive;
}
});
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 : {

@@ -16,6 +21,6 @@ default: obj

return _postcss.default.atRule({
name: 'responsive'
}).append((0, _cloneNodes).default(Array.isArray(rules) ? rules : [
name: "responsive"
}).append((0, _cloneNodes.default)(Array.isArray(rules) ? rules : [
rules
]));
}

@@ -5,3 +5,8 @@ "use strict";

});
exports.tap = tap;
Object.defineProperty(exports, "tap", {
enumerable: true,
get: function() {
return tap;
}
});
function tap(value, mutator) {

@@ -8,0 +13,0 @@ mutator(value);

@@ -5,6 +5,10 @@ "use strict";

});
exports.default = toColorValue;
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return toColorValue;
}
});
function toColorValue(maybeFunction) {
return typeof maybeFunction === 'function' ? maybeFunction({
}) : maybeFunction;
return typeof maybeFunction === "function" ? maybeFunction({}) : maybeFunction;
}

@@ -1,9 +0,32 @@

"use strict";
/**
* Parse a path string into an array of path segments.
*
* Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
*
* Example:
* a -> ['a']
* a.b.c -> ['a', 'b', 'c']
* a[b].c -> ['a', 'b', 'c']
* a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
* a[b][c][d] -> ['a', 'b', 'c', 'd']
*
* @param {string|string[]} path
**/ "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.toPath = toPath;
Object.defineProperty(exports, "toPath", {
enumerable: true,
get: function() {
return toPath;
}
});
function toPath(path) {
if (Array.isArray(path)) return path;
return path.split(/[\.\]\[]+/g);
let openBrackets = path.split("[").length - 1;
let closedBrackets = path.split("]").length - 1;
if (openBrackets !== closedBrackets) {
throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`);
}
return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean);
}

@@ -5,5 +5,11 @@ "use strict";

});
exports.default = transformThemeValue;
var _postcss = _interopRequireDefault(require("postcss"));
function _interopRequireDefault(obj) {
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return transformThemeValue;
}
});
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 : {

@@ -15,23 +21,35 @@ default: obj

if ([
'fontSize',
'outline'
"fontSize",
"outline"
].includes(themeSection)) {
return (value)=>Array.isArray(value) ? value[0] : value
;
return (value)=>{
if (typeof value === "function") value = value({});
if (Array.isArray(value)) value = value[0];
return value;
};
}
if (themeSection === "fontFamily") {
return (value)=>{
if (typeof value === "function") value = value({});
let families = Array.isArray(value) && (0, _isPlainObject.default)(value[1]) ? value[0] : value;
return Array.isArray(families) ? families.join(", ") : families;
};
}
if ([
'fontFamily',
'boxShadow',
'transitionProperty',
'transitionDuration',
'transitionDelay',
'transitionTimingFunction',
'backgroundImage',
'backgroundSize',
'backgroundColor',
'cursor',
'animation',
"boxShadow",
"transitionProperty",
"transitionDuration",
"transitionDelay",
"transitionTimingFunction",
"backgroundImage",
"backgroundSize",
"backgroundColor",
"cursor",
"animation"
].includes(themeSection)) {
return (value)=>Array.isArray(value) ? value.join(', ') : value
;
return (value)=>{
if (typeof value === "function") value = value({});
if (Array.isArray(value)) value = value.join(", ");
return value;
};
}

@@ -41,16 +59,18 @@ // For backwards compatibility reasons, before we switched to underscores

if ([
'gridTemplateColumns',
'gridTemplateRows',
'objectPosition'
"gridTemplateColumns",
"gridTemplateRows",
"objectPosition"
].includes(themeSection)) {
return (value)=>typeof value === 'string' ? _postcss.default.list.comma(value).join(' ') : value
;
return (value)=>{
if (typeof value === "function") value = value({});
if (typeof value === "string") value = _postcss.default.list.comma(value).join(" ");
return value;
};
}
if (themeSection === 'colors') {
return (value)=>typeof value === 'function' ? value({
}) : value
;
}
return (value)=>value
;
return (value, opts = {})=>{
if (typeof value === "function") {
value = value(opts);
}
return value;
};
}

@@ -5,7 +5,19 @@ "use strict";

});
exports.withAlphaValue = withAlphaValue;
exports.default = withAlphaVariable;
var _color = require("./color");
function _export(target, all) {
for(var name in all)Object.defineProperty(target, name, {
enumerable: true,
get: all[name]
});
}
_export(exports, {
withAlphaValue: function() {
return withAlphaValue;
},
default: function() {
return withAlphaVariable;
}
});
const _color = require("./color");
function withAlphaValue(color, alphaValue, defaultValue) {
if (typeof color === 'function') {
if (typeof color === "function") {
return color({

@@ -15,7 +27,9 @@ opacityValue: alphaValue

}
let parsed = (0, _color).parseColor(color);
let parsed = (0, _color.parseColor)(color, {
loose: true
});
if (parsed === null) {
return defaultValue;
}
return (0, _color).formatColor({
return (0, _color.formatColor)({
...parsed,

@@ -27,5 +41,5 @@ alpha: alphaValue

let properties = [].concat(property);
if (typeof color === 'function') {
if (typeof color === "function") {
return {
[variable]: '1',
[variable]: "1",
...Object.fromEntries(properties.map((p)=>{

@@ -42,3 +56,3 @@ return [

}
const parsed = (0, _color).parseColor(color);
const parsed = (0, _color.parseColor)(color);
if (parsed === null) {

@@ -48,4 +62,3 @@ return Object.fromEntries(properties.map((p)=>[

color
]
));
]));
}

@@ -57,11 +70,10 @@ if (parsed.alpha !== undefined) {

color
]
));
]));
}
return {
[variable]: '1',
[variable]: "1",
...Object.fromEntries(properties.map((p)=>{
return [
p,
(0, _color).formatColor({
(0, _color.formatColor)({
...parsed,

@@ -68,0 +80,0 @@ alpha: `var(${variable})`

@@ -1,12 +0,2 @@

let nesting = require('./plugin')
module.exports = (opts) => {
return {
postcssPlugin: 'tailwindcss/nesting',
Once(root, { result }) {
return nesting(opts)(root, result)
},
}
}
module.exports.postcss = true
let nesting = require('../lib/postcss-plugins/nesting')
module.exports = (nesting.__esModule ? nesting : { default: nesting }).default
{
"name": "tailwindcss",
"version": "0.0.0-insiders.6d04c2d",
"version": "0.0.0-insiders.6d9ae82",
"description": "A utility-first CSS framework for rapidly building custom user interfaces.",
"license": "MIT",
"main": "lib/index.js",
"style": "dist/tailwind.css",
"types": "types/index.d.ts",
"repository": "https://github.com/tailwindlabs/tailwindcss.git",

@@ -15,20 +15,18 @@ "bugs": "https://github.com/tailwindlabs/tailwindcss/issues",

},
"contributors": [
"Adam Wathan <adam.wathan@gmail.com>",
"Jonathan Reinink <jonathan@reinink.ca>",
"David Hemphill <davidlee.hemphill@gmail.com>"
],
"scripts": {
"preswcify": "npm run generate:plugin-list && 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",
"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 .",
"pretest": "npm run generate:plugin-list",
"test": "cross-env TAILWIND_MODE=build jest",
"pretest": "npm run generate",
"test": "jest",
"test:integrations": "npm run test --prefix ./integrations",
"install:integrations": "node scripts/install-integrations.js",
"posttest": "npm run style",
"generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js"
"generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js",
"generate:types": "node -r @swc/register scripts/generate-types.js",
"generate": "npm run generate:plugin-list && npm run generate:types",
"release-channel": "node ./scripts/release-channel.js",
"release-notes": "node ./scripts/release-notes.js",
"prepublishOnly": "npm install --force && npm run build"
},

@@ -41,4 +39,6 @@ "files": [

"scripts/*.js",
"stubs/*.stub.js",
"stubs/*",
"nesting/*",
"types/**/*",
"*.d.ts",
"*.css",

@@ -48,46 +48,45 @@ "*.js"

"devDependencies": {
"@swc/cli": "^0.1.50",
"@swc/core": "^1.2.92",
"@swc/jest": "^0.1.5",
"@swc/register": "^0.1.7",
"autoprefixer": "^10.3.6",
"cross-env": "^7.0.3",
"cssnano": "^5.0.8",
"esbuild": "^0.13.2",
"eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.2.4",
"jest-diff": "^27.2.0",
"postcss": "^8.3.8",
"postcss-cli": "^8.3.1",
"prettier": "^2.4.1",
"rimraf": "^3.0.0"
"@swc/cli": "^0.1.62",
"@swc/core": "^1.3.55",
"@swc/jest": "^0.2.26",
"@swc/register": "^0.1.10",
"autoprefixer": "^10.4.14",
"browserslist": "^4.21.5",
"concurrently": "^8.0.1",
"cssnano": "^6.1.2",
"esbuild": "^0.20.2",
"eslint": "^8.39.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.6.0",
"jest-diff": "^29.6.0",
"lightningcss": "1.24.1",
"prettier": "^2.8.8",
"rimraf": "^5.0.0",
"source-map-js": "^1.0.2",
"turbo": "^1.9.3"
},
"peerDependencies": {
"autoprefixer": "^10.0.2",
"postcss": "^8.0.9"
},
"dependencies": {
"arg": "^5.0.1",
"chalk": "^4.1.2",
"chokidar": "^3.5.2",
"color-name": "^1.1.4",
"cosmiconfig": "^7.0.1",
"detective": "^5.2.0",
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
"chokidar": "^3.5.3",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
"fast-glob": "^3.2.7",
"fast-glob": "^3.3.0",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
"jiti": "^1.21.0",
"lilconfig": "^2.1.0",
"micromatch": "^4.0.5",
"normalize-path": "^3.0.0",
"object-hash": "^2.2.0",
"postcss-js": "^3.0.3",
"postcss-load-config": "^3.1.0",
"postcss-nested": "5.0.6",
"postcss-selector-parser": "^6.0.6",
"postcss-value-parser": "^4.1.0",
"quick-lru": "^5.1.1",
"resolve": "^1.20.0",
"tmp": "^0.2.1"
"object-hash": "^3.0.0",
"picocolors": "^1.0.0",
"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"
},

@@ -107,11 +106,17 @@ "browserslist": [

"/node_modules/",
"/integrations/"
"/integrations/",
"/standalone-cli/",
"\\.test\\.skip\\.js$"
],
"transformIgnorePatterns": [
"node_modules/(?!lightningcss)"
],
"transform": {
"\\.js$": "@swc/jest"
"\\.js$": "@swc/jest",
"\\.ts$": "@swc/jest"
}
},
"engines": {
"node": ">=12.13.0"
"node": ">=14.0.0"
}
}

@@ -1,1 +0,2 @@

module.exports = require('./lib/public/create-plugin').default
let createPlugin = require('./lib/public/create-plugin')
module.exports = (createPlugin.__esModule ? createPlugin : { default: createPlugin }).default

@@ -1,16 +0,23 @@

<p>
<a href="https://tailwindcss.com/" target="_blank">
<img alt="Tailwind CSS" width="350" src="https://refactoringui.nyc3.cdn.digitaloceanspaces.com/tailwind-logo-sticker.svg">
</a><br>
A utility-first CSS framework for rapidly building custom user interfaces.
<p align="center">
<a href="https://tailwindcss.com" target="_blank">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-dark.svg">
<source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg">
<img alt="Tailwind CSS" src="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg" width="350" height="70" style="max-width: 100%;">
</picture>
</a>
</p>
<p>
<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>
<p align="center">
A utility-first CSS framework for rapidly building custom user interfaces.
</p>
<p align="center">
<a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci.yml?branch=main" 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>
<a href="https://github.com/tailwindcss/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a>
<a href="https://github.com/tailwindcss/tailwindcss/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
<a href="https://github.com/tailwindcss/tailwindcss/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
</p>
------
---

@@ -33,2 +40,2 @@ ## Documentation

If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/master/.github/CONTRIBUTING.md) **before submitting a pull request**.
If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**.

@@ -1,1 +0,2 @@

module.exports = require('./lib/public/resolve-config').default
let resolveConfig = require('./lib/public/resolve-config')
module.exports = (resolveConfig.__esModule ? resolveConfig : { default: resolveConfig }).default

@@ -1,3 +0,9 @@

export let postcss = require('postcss')
export function lazyPostcss() {
return require('postcss')
}
export function lazyPostcssImport() {
return require('postcss-import')
}
export function lazyAutoprefixer() {

@@ -4,0 +10,0 @@ return require('autoprefixer')

#!/usr/bin/env node
import { postcss, lazyCssnano, lazyAutoprefixer } from '../peers/index.js'
import chokidar from 'chokidar'
import path from 'path'
import arg from 'arg'
import fs from 'fs'
import postcssrc from 'postcss-load-config'
import { cosmiconfig } from 'cosmiconfig'
import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API
import tailwind from './processTailwindFeatures'
import resolveConfigInternal from '../resolveConfig'
import fastGlob from 'fast-glob'
import getModuleDependencies from './lib/getModuleDependencies'
import log from './util/log'
import packageJson from '../package.json'
import normalizePath from 'normalize-path'
let env = {
DEBUG: process.env.DEBUG !== undefined,
}
// ---
function indentRecursive(node, indent = 0) {
node.each &&
node.each((child, i) => {
if (!child.raws.before || !child.raws.before.trim() || child.raws.before.includes('\n')) {
child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}`
}
child.raws.after = `\n${' '.repeat(indent)}`
indentRecursive(child, indent + 1)
})
}
function formatNodes(root) {
indentRecursive(root)
if (root.first) {
root.first.raws.before = ''
}
}
function help({ message, usage, commands, options }) {
let indent = 2
// Render header
console.log()
console.log(`${packageJson.name} v${packageJson.version}`)
// Render message
if (message) {
console.log()
for (let msg of message.split('\n')) {
console.log(msg)
}
}
// Render usage
if (usage && usage.length > 0) {
console.log()
console.log('Usage:')
for (let example of usage) {
console.log(' '.repeat(indent), example)
}
}
// Render commands
if (commands && commands.length > 0) {
console.log()
console.log('Commands:')
for (let command of commands) {
console.log(' '.repeat(indent), command)
}
}
// Render options
if (options) {
let groupedOptions = {}
for (let [key, value] of Object.entries(options)) {
if (typeof value === 'object') {
groupedOptions[key] = { ...value, flags: [key] }
} else {
groupedOptions[value].flags.push(key)
}
}
console.log()
console.log('Options:')
for (let { flags, description, deprecated } of Object.values(groupedOptions)) {
if (deprecated) continue
if (flags.length === 1) {
console.log(
' '.repeat(indent + 4 /* 4 = "-i, ".length */),
flags.slice().reverse().join(', ').padEnd(20, ' '),
description
)
} else {
console.log(
' '.repeat(indent),
flags.slice().reverse().join(', ').padEnd(24, ' '),
description
)
}
}
}
console.log()
}
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 `tailwind.config.js` file' },
'--postcss': { type: Boolean, description: 'Initialize a `postcss.config.js` 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' },
'--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',
},
},
}
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()
// ---
function init() {
let messages = []
let tailwindConfigLocation = path.resolve(args['_'][1] ?? './tailwind.config.js')
if (fs.existsSync(tailwindConfigLocation)) {
messages.push(`${path.basename(tailwindConfigLocation)} already exists.`)
} else {
let stubFile = fs.readFileSync(
args['--full']
? path.resolve(__dirname, '../stubs/defaultConfig.stub.js')
: path.resolve(__dirname, '../stubs/simpleConfig.stub.js'),
'utf8'
)
// Change colors import
stubFile = stubFile.replace('../colors', 'tailwindcss/colors')
fs.writeFileSync(tailwindConfigLocation, stubFile, 'utf8')
messages.push(`Created Tailwind CSS config file: ${path.basename(tailwindConfigLocation)}`)
}
if (args['--postcss']) {
let postcssConfigLocation = path.resolve('./postcss.config.js')
if (fs.existsSync(postcssConfigLocation)) {
messages.push(`${path.basename(postcssConfigLocation)} already exists.`)
} else {
let stubFile = fs.readFileSync(
path.resolve(__dirname, '../stubs/defaultPostCssConfig.stub.js'),
'utf8'
)
fs.writeFileSync(postcssConfigLocation, stubFile, 'utf8')
messages.push(`Created PostCSS config file: ${path.basename(postcssConfigLocation)}`)
}
}
if (messages.length > 0) {
console.log()
for (let message of messages) {
console.log(message)
}
}
}
async function build() {
let input = args['--input']
let output = args['--output']
let shouldWatch = args['--watch']
let includePostCss = args['--postcss']
// TODO: Deprecate this in future versions
if (!input && args['_'][1]) {
console.error('[deprecation] Running tailwindcss without -i, please provide an input file.')
input = args['--input'] = args['_'][1]
}
if (input && !fs.existsSync((input = path.resolve(input)))) {
console.error(`Specified input file ${args['--input']} does not exist.`)
process.exit(9)
}
if (args['--config'] && !fs.existsSync((args['--config'] = path.resolve(args['--config'])))) {
console.error(`Specified config file ${args['--config']} does not exist.`)
process.exit(9)
}
let configPath = args['--config']
? args['--config']
: ((defaultPath) => (fs.existsSync(defaultPath) ? defaultPath : null))(
path.resolve('./tailwind.config.js')
)
async function loadPostCssPlugins() {
let customPostCssPath = typeof args['--postcss'] === 'string' ? args['--postcss'] : undefined
let { plugins: configPlugins } = customPostCssPath
? await (async () => {
let file = path.resolve(customPostCssPath)
// Implementation, see: https://unpkg.com/browse/postcss-load-config@3.0.1/src/index.js
let { config = {} } = await cosmiconfig('postcss').load(file)
if (typeof config === 'function') {
config = config()
} else {
config = Object.assign({}, config)
}
if (!config.plugins) {
config.plugins = []
}
return { plugins: loadPlugins(config, file) }
})()
: await postcssrc()
let configPluginTailwindIdx = configPlugins.findIndex((plugin) => {
if (typeof plugin === 'function' && plugin.name === 'tailwindcss') {
return true
}
if (typeof plugin === 'object' && plugin !== null && plugin.postcssPlugin === 'tailwindcss') {
return true
}
return false
})
let beforePlugins =
configPluginTailwindIdx === -1 ? [] : configPlugins.slice(0, configPluginTailwindIdx)
let afterPlugins =
configPluginTailwindIdx === -1
? configPlugins
: configPlugins.slice(configPluginTailwindIdx + 1)
return [beforePlugins, afterPlugins]
}
function resolveConfig() {
let config = configPath ? require(configPath) : {}
let resolvedConfig = resolveConfigInternal(config)
if (args['--purge']) {
log.warn('purge-flag-deprecated', [
'The `--purge` flag has been deprecated.',
'Please use `--content` instead.',
])
if (!args['--content']) {
args['--content'] = args['--purge']
}
}
if (args['--content']) {
resolvedConfig.content = args['--content'].split(/(?<!{[^}]+),/)
}
return resolvedConfig
}
function extractFileGlobs(config) {
return config.content.files
.filter((file) => {
// Strings in this case are files / globs. If it is something else,
// like an object it's probably a raw content object. But this object
// is not watchable, so let's remove it.
return typeof file === 'string'
})
.map((glob) => normalizePath(glob))
}
function extractRawContent(config) {
return config.content.files.filter((file) => {
return typeof file === 'object' && file !== null
})
}
function getChangedContent(config) {
let changedContent = []
// Resolve globs from the content config
let globs = extractFileGlobs(config)
let files = fastGlob.sync(globs)
for (let file of files) {
changedContent.push({
content: fs.readFileSync(path.resolve(file), 'utf8'),
extension: path.extname(file).slice(1),
})
}
// Resolve raw content in the tailwind config
for (let { raw: content, extension = 'html' } of extractRawContent(config)) {
changedContent.push({ content, extension })
}
return changedContent
}
async function buildOnce() {
let config = resolveConfig()
let changedContent = getChangedContent(config)
let tailwindPlugin = () => {
return {
postcssPlugin: 'tailwindcss',
Once(root, { result }) {
tailwind(({ createContext }) => {
return () => {
return createContext(config, changedContent)
}
})(root, result)
},
}
}
tailwindPlugin.postcss = true
let [beforePlugins, afterPlugins] = includePostCss ? await loadPostCssPlugins() : [[], []]
let plugins = [
...beforePlugins,
tailwindPlugin,
!args['--minify'] && formatNodes,
...afterPlugins,
!args['--no-autoprefixer'] &&
(() => {
// Try to load a local `autoprefixer` version first
try {
return require('autoprefixer')
} catch {}
return lazyAutoprefixer()
})(),
args['--minify'] &&
(() => {
let options = { preset: ['default', { cssDeclarationSorter: false }] }
// Try to load a local `cssnano` version first
try {
return require('cssnano')
} catch {}
return lazyCssnano()(options)
})(),
].filter(Boolean)
let processor = postcss(plugins)
function processCSS(css) {
let start = process.hrtime.bigint()
return Promise.resolve()
.then(() => (output ? fs.promises.mkdir(path.dirname(output), { recursive: true }) : null))
.then(() => processor.process(css, { from: input, to: output }))
.then((result) => {
if (!output) {
return process.stdout.write(result.css)
}
return Promise.all(
[
fs.promises.writeFile(output, result.css, () => true),
result.map && fs.writeFile(output + '.map', result.map.toString(), () => true),
].filter(Boolean)
)
})
.then(() => {
let end = process.hrtime.bigint()
console.error()
console.error('Done in', (end - start) / BigInt(1e6) + 'ms.')
})
}
let css = input
? fs.readFileSync(path.resolve(input), 'utf8')
: '@tailwind base; @tailwind components; @tailwind utilities'
return processCSS(css)
}
let context = null
async function startWatcher() {
let changedContent = []
let configDependencies = []
let contextDependencies = new Set()
let watcher = null
function refreshConfig() {
env.DEBUG && console.time('Module dependencies')
for (let file of configDependencies) {
delete require.cache[require.resolve(file)]
}
if (configPath) {
configDependencies = getModuleDependencies(configPath).map(({ file }) => file)
for (let dependency of configDependencies) {
contextDependencies.add(dependency)
}
}
env.DEBUG && console.timeEnd('Module dependencies')
return resolveConfig()
}
let [beforePlugins, afterPlugins] = includePostCss ? await loadPostCssPlugins() : [[], []]
let plugins = [
...beforePlugins,
'__TAILWIND_PLUGIN_POSITION__',
!args['--minify'] && formatNodes,
...afterPlugins,
!args['--no-autoprefixer'] &&
(() => {
// Try to load a local `autoprefixer` version first
try {
return require('autoprefixer')
} catch {}
return lazyAutoprefixer()
})(),
args['--minify'] &&
(() => {
let options = { preset: ['default', { cssDeclarationSorter: false }] }
// Try to load a local `cssnano` version first
try {
return require('cssnano')
} catch {}
return lazyCssnano()(options)
})(),
].filter(Boolean)
async function rebuild(config) {
env.DEBUG && console.time('Finished in')
let tailwindPlugin = () => {
return {
postcssPlugin: 'tailwindcss',
Once(root, { result }) {
env.DEBUG && console.time('Compiling CSS')
tailwind(({ createContext }) => {
console.error()
console.error('Rebuilding...')
return () => {
if (context !== null) {
context.changedContent = changedContent.splice(0)
return context
}
env.DEBUG && console.time('Creating context')
context = createContext(config, changedContent.splice(0))
env.DEBUG && console.timeEnd('Creating context')
return context
}
})(root, result)
env.DEBUG && console.timeEnd('Compiling CSS')
},
}
}
tailwindPlugin.postcss = true
let tailwindPluginIdx = plugins.indexOf('__TAILWIND_PLUGIN_POSITION__')
let copy = plugins.slice()
copy.splice(tailwindPluginIdx, 1, tailwindPlugin)
let processor = postcss(copy)
function processCSS(css) {
let start = process.hrtime.bigint()
return Promise.resolve()
.then(() =>
output ? fs.promises.mkdir(path.dirname(output), { recursive: true }) : null
)
.then(() => processor.process(css, { from: input, to: output }))
.then(async (result) => {
for (let message of result.messages) {
if (message.type === 'dependency') {
contextDependencies.add(message.file)
}
}
watcher.add([...contextDependencies])
if (!output) {
return process.stdout.write(result.css)
}
await Promise.all(
[
fs.promises.writeFile(output, result.css, () => true),
result.map && fs.writeFile(output + '.map', result.map.toString(), () => true),
].filter(Boolean)
)
})
.then(() => {
let end = process.hrtime.bigint()
console.error('Done in', (end - start) / BigInt(1e6) + 'ms.')
})
.catch((err) => {
if (err.name === 'CssSyntaxError') {
console.error(err.toString())
} else {
console.error(err)
}
})
}
let css = input
? fs.readFileSync(path.resolve(input), 'utf8')
: '@tailwind base; @tailwind components; @tailwind utilities'
let result = await processCSS(css)
env.DEBUG && console.timeEnd('Finished in')
return result
}
let config = refreshConfig(configPath)
if (input) {
contextDependencies.add(path.resolve(input))
}
watcher = chokidar.watch([...contextDependencies, ...extractFileGlobs(config)], {
ignoreInitial: true,
})
let chain = Promise.resolve()
watcher.on('change', async (file) => {
if (contextDependencies.has(file)) {
env.DEBUG && console.time('Resolve config')
context = null
config = refreshConfig(configPath)
env.DEBUG && console.timeEnd('Resolve config')
env.DEBUG && console.time('Watch new files')
let globs = extractFileGlobs(config)
watcher.add(configDependencies)
watcher.add(globs)
env.DEBUG && console.timeEnd('Watch new files')
chain = chain.then(async () => {
changedContent.push(...getChangedContent(config))
await rebuild(config)
})
} else {
chain = chain.then(async () => {
changedContent.push({
content: fs.readFileSync(path.resolve(file), 'utf8'),
extension: path.extname(file).slice(1),
})
await rebuild(config)
})
}
})
watcher.on('add', async (file) => {
chain = chain.then(async () => {
changedContent.push({
content: fs.readFileSync(path.resolve(file), 'utf8'),
extension: path.extname(file).slice(1),
})
await rebuild(config)
})
})
chain = chain.then(() => {
changedContent.push(...getChangedContent(config))
return rebuild(config)
})
}
if (shouldWatch) {
/* Abort the watcher if stdin is closed to avoid zombie processes */
process.stdin.on('end', () => process.exit(0))
process.stdin.resume()
startWatcher()
} else {
buildOnce()
}
}
module.exports = require('./cli/index')

@@ -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","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","fontSmoothing","placeholderColor","placeholderOpacity","caretColor","accentColor","opacity","backgroundBlendMode","mixBlendMode","boxShadow","outline","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","size","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","textWrap","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","contain","content","forcedColorAdjust"]

@@ -1,11 +0,19 @@

import chalk from 'chalk'
import colors from 'picocolors'
import log from './util/log'
let defaults = {
optimizeUniversalDefaults: true,
optimizeUniversalDefaults: false,
generalizedModifiers: true,
disableColorOpacityUtilitiesByDefault: false,
relativeContentPathsByDefault: false,
}
let featureFlags = {
future: [],
experimental: ['optimizeUniversalDefaults'],
future: [
'hoverOnlyWhenSupported',
'respectDefaultRingColorOpacity',
'disableColorOpacityUtilitiesByDefault',
'relativeContentPathsByDefault',
],
experimental: ['optimizeUniversalDefaults', 'generalizedModifiers'],
}

@@ -44,3 +52,3 @@

let changes = experimentalFlagsEnabled(config)
.map((s) => chalk.yellow(s))
.map((s) => colors.yellow(s))
.join(', ')

@@ -47,0 +55,0 @@

@@ -1,34 +0,1 @@

import setupTrackingContext from './lib/setupTrackingContext'
import setupWatchingContext from './lib/setupWatchingContext'
import processTailwindFeatures from './processTailwindFeatures'
import { env } from './lib/sharedState'
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) {
let setupContext =
env.TAILWIND_MODE === 'watch'
? setupWatchingContext(configOrPath)
: setupTrackingContext(configOrPath)
processTailwindFeatures(setupContext)(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')

@@ -8,3 +8,3 @@ let comparisonMap = {

export default function collapseAdjacentRules() {
return (root) => {
function collapseRulesIn(root) {
let currentRule = null

@@ -33,3 +33,7 @@ root.each((node) => {

) {
currentRule.append(node.nodes)
// An AtRule may not have children (for example if we encounter duplicate @import url(…) rules)
if (node.nodes) {
currentRule.append(node.nodes)
}
node.remove()

@@ -40,3 +44,18 @@ } else {

})
// After we've collapsed adjacent rules & at-rules, we need to collapse
// adjacent rules & at-rules that are children of at-rules.
// We do not care about nesting rules because Tailwind CSS
// explicitly does not handle rule nesting on its own as
// the user is expected to use a nesting plugin
root.each((node) => {
if (node.type === 'atrule') {
collapseRulesIn(node)
}
})
}
return (root) => {
collapseRulesIn(root)
}
}
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'
import buildMediaQuery from '../util/buildMediaQuery'
import { toPath } from '../util/toPath'
import { withAlphaValue } from '../util/withAlphaVariable'
import { parseColorFormat } from '../util/pluginUtils'
import log from '../util/log'

@@ -39,8 +43,6 @@ function isObject(input) {

function validatePath(config, path, defaultValue) {
const pathString = Array.isArray(path)
? pathToString(path)
: path.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
function validatePath(config, path, defaultValue, themeOpts = {}) {
const pathString = Array.isArray(path) ? pathToString(path) : path.replace(/^['"]+|['"]+$/g, '')
const pathSegments = Array.isArray(path) ? path : toPath(pathString)
const value = dlv(config.theme, pathString, defaultValue)
const value = dlv(config.theme, pathSegments, defaultValue)

@@ -117,3 +119,3 @@ if (value === undefined) {

isValid: true,
value: transformThemeValue(themeSection)(value),
value: transformThemeValue(themeSection)(value, themeOpts),
}

@@ -149,2 +151,5 @@ }

function resolveFunctions(node, input, functions) {
let hasAnyFn = Object.keys(functions).some((fn) => input.includes(`${fn}(`))
if (!hasAnyFn) return input
return parseValue(input)

@@ -162,6 +167,47 @@ .walk((vNode) => {

export default function ({ tailwindConfig: config }) {
/**
* @param {string} path
* @returns {Iterable<[path: string, alpha: string|undefined]>}
*/
function* toPaths(path) {
// Strip quotes from beginning and end of string
// This allows the alpha value to be present inside of quotes
path = path.replace(/^['"]+|['"]+$/g, '')
let matches = path.match(/^([^\s]+)(?![^\[]*\])(?:\s*\/\s*([^\/\s]+))$/)
let alpha = undefined
yield [path, undefined]
if (matches) {
path = matches[1]
alpha = matches[2]
yield [path, alpha]
}
}
/**
*
* @param {any} config
* @param {string} path
* @param {any} defaultValue
*/
function resolvePath(config, path, defaultValue) {
const results = Array.from(toPaths(path)).map(([path, alpha]) => {
return Object.assign(validatePath(config, path, defaultValue, { opacityValue: alpha }), {
resolvedPath: path,
alpha,
})
})
return results.find((result) => result.isValid) ?? results[0]
}
export default function (context) {
let config = context.tailwindConfig
let functions = {
theme: (node, path, ...defaultValue) => {
const { isValid, value, error } = validatePath(
let { isValid, value, error, alpha } = resolvePath(
config,

@@ -173,5 +219,34 @@ path,

if (!isValid) {
let parentNode = node.parent
let candidate = parentNode?.raws.tailwind?.candidate
if (parentNode && candidate !== undefined) {
// Remove this utility from any caches
context.markInvalidUtilityNode(parentNode)
// Remove the CSS node from the markup
parentNode.remove()
// Show a warning
log.warn('invalid-theme-key-in-class', [
`The utility \`${candidate}\` contains an invalid theme value and was not generated.`,
])
return
}
throw node.error(error)
}
let maybeColor = parseColorFormat(value)
let isColorFunction = maybeColor !== undefined && typeof maybeColor === 'function'
if (alpha !== undefined || isColorFunction) {
if (alpha === undefined) {
alpha = 1.0
}
value = withAlphaValue(maybeColor, alpha, maybeColor)
}
return value

@@ -181,8 +256,10 @@ },

screen = screen.replace(/^['"]+/g, '').replace(/['"]+$/g, '')
let screens = normalizeScreens(config.theme.screens)
let screenDefinition = screens.find(({ name }) => name === screen)
if (config.theme.screens[screen] === undefined) {
if (!screenDefinition) {
throw node.error(`The '${screen}' screen does not exist in your theme.`)
}
return buildMediaQuery(config.theme.screens[screen])
return buildMediaQuery(screenDefinition)
},

@@ -189,0 +266,0 @@ }

import postcss from 'postcss'
import parser from 'postcss-selector-parser'
import { resolveMatches } from './generateRules'
import bigSign from '../util/bigSign'
import escapeClassName from '../util/escapeClassName'
import { applyImportantSelector } from '../util/applyImportantSelector'
import { movePseudos } from '../util/pseudoElements'
/** @typedef {Map<string, [any, import('postcss').Rule[]]>} ApplyCache */
function extractClasses(node) {
/** @type {Map<string, Set<string>>} */
let groups = new Map()
let container = postcss.root({ nodes: [node.clone()] })
container.walkRules((rule) => {
parser((selectors) => {
selectors.walkClasses((classSelector) => {
let parentSelector = classSelector.parent.toString()
let classes = groups.get(parentSelector)
if (!classes) {
groups.set(parentSelector, (classes = new Set()))
}
classes.add(classSelector.value)
})
}).processSync(rule.selector)
})
let normalizedGroups = Array.from(groups.values(), (classes) => Array.from(classes))
let classes = normalizedGroups.flat()
return Object.assign(classes, { groups: normalizedGroups })
}
let selectorExtractor = parser()
/**
* @param {string} ruleSelectors
*/
function extractSelectors(ruleSelectors) {
return selectorExtractor.astSync(ruleSelectors)
}
function extractBaseCandidates(candidates, separator) {
let baseClasses = new Set()
for (let candidate of candidates) {
baseClasses.add(candidate.split(separator).pop())
}
return Array.from(baseClasses)
}
function prefix(context, selector) {

@@ -11,2 +62,126 @@ let prefix = context.tailwindConfig.prefix

function* pathToRoot(node) {
yield node
while (node.parent) {
yield node.parent
node = node.parent
}
}
/**
* Only clone the node itself and not its children
*
* @param {*} node
* @param {*} overrides
* @returns
*/
function shallowClone(node, overrides = {}) {
let children = node.nodes
node.nodes = []
let tmp = node.clone(overrides)
node.nodes = children
return tmp
}
/**
* Clone just the nodes all the way to the top that are required to represent
* this singular rule in the tree.
*
* For example, if we have CSS like this:
* ```css
* @media (min-width: 768px) {
* @supports (display: grid) {
* .foo {
* display: grid;
* grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
* }
* }
*
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
*
* .baz {
* color: orange;
* }
* }
* ```
*
* And we're cloning `.bar` it'll return a cloned version of what's required for just that single node:
*
* ```css
* @media (min-width: 768px) {
* @supports (backdrop-filter: blur(1px)) {
* .bar {
* backdrop-filter: blur(1px);
* }
* }
* }
* ```
*
* @param {import('postcss').Node} node
*/
function nestedClone(node) {
for (let parent of pathToRoot(node)) {
if (node === parent) {
continue
}
if (parent.type === 'root') {
break
}
node = shallowClone(parent, {
nodes: [node],
})
}
return node
}
/**
* @param {import('postcss').Root} root
*/
function buildLocalApplyCache(root, context) {
/** @type {ApplyCache} */
let cache = new Map()
root.walkRules((rule) => {
// Ignore rules generated by Tailwind
for (let node of pathToRoot(rule)) {
if (node.raws.tailwind?.layer !== undefined) {
return
}
}
// Clone what's required to represent this singular rule in the tree
let container = nestedClone(rule)
let sort = context.offsets.create('user')
for (let className of extractClasses(rule)) {
let list = cache.get(className) || []
cache.set(className, list)
list.push([
{
layer: 'user',
sort,
important: false,
},
container,
])
}
})
return cache
}
/**
* @returns {ApplyCache}
*/
function buildApplyCache(applyCandidates, context) {

@@ -39,2 +214,39 @@ for (let candidate of applyCandidates) {

/**
* Build a cache only when it's first used
*
* @param {() => ApplyCache} buildCacheFn
* @returns {ApplyCache}
*/
function lazyCache(buildCacheFn) {
let cache = null
return {
get: (name) => {
cache = cache || buildCacheFn()
return cache.get(name)
},
has: (name) => {
cache = cache || buildCacheFn()
return cache.has(name)
},
}
}
/**
* Take a series of multiple caches and merge
* them so they act like one large cache
*
* @param {ApplyCache[]} caches
* @returns {ApplyCache}
*/
function combineCaches(caches) {
return {
get: (name) => caches.flatMap((cache) => cache.get(name) || []),
has: (name) => caches.some((cache) => cache.has(name)),
}
}
function extractApplyCandidates(params) {

@@ -50,44 +262,3 @@ let candidates = params.split(/[\s\t\n]+/g)

function partitionApplyParents(root) {
let applyParents = new Set()
root.walkAtRules('apply', (rule) => {
applyParents.add(rule.parent)
})
for (let rule of applyParents) {
let nodeGroups = []
let lastGroup = []
for (let node of rule.nodes) {
if (node.type === 'atrule' && node.name === 'apply') {
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup)
lastGroup = []
}
nodeGroups.push([node])
} else {
lastGroup.push(node)
}
}
if (lastGroup.length > 0) {
nodeGroups.push(lastGroup)
}
if (nodeGroups.length === 1) {
continue
}
for (let group of [...nodeGroups].reverse()) {
let newParent = rule.clone({ nodes: [] })
newParent.append(group)
rule.after(newParent)
}
rule.remove()
}
}
function processApply(root, context) {
function processApply(root, context, localCache) {
let applyCandidates = new Set()

@@ -108,141 +279,354 @@

// Start the @apply process if we have rules with @apply in them
if (applies.length > 0) {
// Fill up some caches!
let applyClassCache = buildApplyCache(applyCandidates, context)
if (applies.length === 0) {
return
}
/**
* When we have an apply like this:
*
* .abc {
* @apply hover:font-bold;
* }
*
* What we essentially will do is resolve to this:
*
* .abc {
* @apply .hover\:font-bold:hover {
* font-weight: 500;
* }
* }
*
* Notice that the to-be-applied class is `.hover\:font-bold:hover` and that the utility candidate was `hover:font-bold`.
* What happens in this function is that we prepend a `.` and escape the candidate.
* This will result in `.hover\:font-bold`
* Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
*/
// TODO: Should we use postcss-selector-parser for this instead?
function replaceSelector(selector, utilitySelectors, candidate) {
let needle = `.${escapeClassName(candidate)}`
let utilitySelectorsList = utilitySelectors.split(/\s*,\s*/g)
// Fill up some caches!
let applyClassCache = combineCaches([localCache, buildApplyCache(applyCandidates, context)])
return selector
.split(/\s*,\s*/g)
.map((s) => {
let replaced = []
/**
* When we have an apply like this:
*
* .abc {
* @apply hover:font-bold;
* }
*
* What we essentially will do is resolve to this:
*
* .abc {
* @apply .hover\:font-bold:hover {
* font-weight: 500;
* }
* }
*
* Notice that the to-be-applied class is `.hover\:font-bold:hover` and that the utility candidate was `hover:font-bold`.
* What happens in this function is that we prepend a `.` and escape the candidate.
* This will result in `.hover\:font-bold`
* Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
*
* @param {string} selector
* @param {string} utilitySelectors
* @param {string} candidate
*/
function replaceSelector(selector, utilitySelectors, candidate) {
let selectorList = extractSelectors(selector)
let utilitySelectorsList = extractSelectors(utilitySelectors)
let candidateList = extractSelectors(`.${escapeClassName(candidate)}`)
let candidateClass = candidateList.nodes[0].nodes[0]
for (let utilitySelector of utilitySelectorsList) {
let replacedSelector = utilitySelector.replace(needle, s)
if (replacedSelector === utilitySelector) {
continue
}
replaced.push(replacedSelector)
selectorList.each((sel) => {
/** @type {Set<import('postcss-selector-parser').Selector>} */
let replaced = new Set()
utilitySelectorsList.each((utilitySelector) => {
let hasReplaced = false
utilitySelector = utilitySelector.clone()
utilitySelector.walkClasses((node) => {
if (node.value !== candidateClass.value) {
return
}
return replaced.join(', ')
// Don't replace multiple instances of the same class
// This is theoretically correct but only partially
// We'd need to generate every possible permutation of the replacement
// For example with `.foo + .foo { … }` and `section { @apply foo; }`
// We'd need to generate all of these:
// - `.foo + .foo`
// - `.foo + section`
// - `section + .foo`
// - `section + section`
if (hasReplaced) {
return
}
// Since you can only `@apply` class names this is sufficient
// We want to replace the matched class name with the selector the user is using
// Ex: Replace `.text-blue-500` with `.foo.bar:is(.something-cool)`
node.replaceWith(...sel.nodes.map((node) => node.clone()))
// Record that we did something and we want to use this new selector
replaced.add(utilitySelector)
hasReplaced = true
})
.join(', ')
}
})
let perParentApplies = new Map()
// Sort tag names before class names (but only sort each group (separated by a combinator)
// separately and not in total)
// This happens when replacing `.bar` in `.foo.bar` with a tag like `section`
for (let sel of replaced) {
let groups = [[]]
for (let node of sel.nodes) {
if (node.type === 'combinator') {
groups.push(node)
groups.push([])
} else {
let last = groups[groups.length - 1]
last.push(node)
}
}
// Collect all apply candidates and their rules
for (let apply of applies) {
let candidates = perParentApplies.get(apply.parent) || []
sel.nodes = []
perParentApplies.set(apply.parent, candidates)
for (let group of groups) {
if (Array.isArray(group)) {
group.sort((a, b) => {
if (a.type === 'tag' && b.type === 'class') {
return -1
} else if (a.type === 'class' && b.type === 'tag') {
return 1
} else if (a.type === 'class' && b.type === 'pseudo' && b.value.startsWith('::')) {
return -1
} else if (a.type === 'pseudo' && a.value.startsWith('::') && b.type === 'class') {
return 1
}
let [applyCandidates, important] = extractApplyCandidates(apply.params)
return 0
})
}
if (apply.parent.type === 'atrule') {
if (apply.parent.name === 'screen') {
const screenType = apply.parent.params
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.`
)
sel.nodes = sel.nodes.concat(group)
}
}
sel.replaceWith(...replaced)
})
return selectorList.toString()
}
let perParentApplies = new Map()
// Collect all apply candidates and their rules
for (let apply of applies) {
let [candidates] = perParentApplies.get(apply.parent) || [[], apply.source]
perParentApplies.set(apply.parent, [candidates, apply.source])
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 @${apply.parent.name}. You can fix this by un-nesting @${apply.parent.name}.`
`@apply is not supported within nested at-rules like @screen. We suggest you write this as @apply ${applyCandidates
.map((c) => `${screenType}:${c}`)
.join(' ')} instead.`
)
}
for (let applyCandidate of applyCandidates) {
if (!applyClassCache.has(applyCandidate)) {
if (applyCandidate === prefix(context, 'group')) {
// TODO: Link to specific documentation page with error code.
throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`)
}
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 applyCandidates) {
if ([prefix(context, 'group'), prefix(context, 'peer')].includes(applyCandidate)) {
// TODO: Link to specific documentation page with error code.
throw apply.error(`@apply should not be used with the '${applyCandidate}' utility`)
}
if (!applyClassCache.has(applyCandidate)) {
throw apply.error(
`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`
)
}
let rules = applyClassCache.get(applyCandidate)
// Verify that we can apply the class
for (let [, rule] of rules) {
if (rule.type === 'atrule') {
continue
}
rule.walkRules(() => {
throw apply.error(
`The \`${applyCandidate}\` class does not exist. If \`${applyCandidate}\` is a custom class, make sure it is defined within a \`@layer\` directive.`
[
`The \`${applyCandidate}\` class cannot be used with \`@apply\` because \`@apply\` does not currently support nested CSS.`,
'Rewrite the selector without nesting or configure the `tailwindcss/nesting` plugin:',
'https://tailwindcss.com/docs/using-with-preprocessors#nesting',
].join('\n')
)
})
}
candidates.push([applyCandidate, important, rules])
}
}
for (let [parent, [candidates, atApplySource]] of perParentApplies) {
let siblings = []
for (let [applyCandidate, important, rules] of candidates) {
let potentialApplyCandidates = [
applyCandidate,
...extractBaseCandidates([applyCandidate], context.tailwindConfig.separator),
]
for (let [meta, node] of rules) {
let parentClasses = extractClasses(parent)
let nodeClasses = extractClasses(node)
// When we encounter a rule like `.dark .a, .b { … }` we only want to be left with `[.dark, .a]` if the base applyCandidate is `.a` or with `[.b]` if the base applyCandidate is `.b`
// So we've split them into groups
nodeClasses = nodeClasses.groups
.filter((classList) =>
classList.some((className) => potentialApplyCandidates.includes(className))
)
.flat()
// Add base utility classes from the @apply node to the list of
// classes to check whether it intersects and therefore results in a
// circular dependency or not.
//
// E.g.:
// .foo {
// @apply hover:a; // This applies "a" but with a modifier
// }
//
// We only have to do that with base classes of the `node`, not of the `parent`
// E.g.:
// .hover\:foo {
// @apply bar;
// }
// .bar {
// @apply foo;
// }
//
// This should not result in a circular dependency because we are
// just applying `.foo` and the rule above is `.hover\:foo` which is
// unrelated. However, if we were to apply `hover:foo` then we _did_
// have to include this one.
nodeClasses = nodeClasses.concat(
extractBaseCandidates(nodeClasses, context.tailwindConfig.separator)
)
let intersects = parentClasses.some((selector) => nodeClasses.includes(selector))
if (intersects) {
throw node.error(
`You cannot \`@apply\` the \`${applyCandidate}\` utility here because it creates a circular dependency.`
)
}
let rules = applyClassCache.get(applyCandidate)
let root = postcss.root({ nodes: [node.clone()] })
candidates.push([applyCandidate, important, rules])
}
}
// Make sure every node in the entire tree points back at the @apply rule that generated it
root.walk((node) => {
node.source = atApplySource
})
for (const [parent, candidates] of perParentApplies) {
let siblings = []
let canRewriteSelector =
node.type !== 'atrule' || (node.type === 'atrule' && node.name !== 'keyframes')
for (let [applyCandidate, important, rules] of candidates) {
for (let [meta, node] of rules) {
let root = postcss.root({ nodes: [node.clone()] })
let canRewriteSelector =
node.type !== 'atrule' || (node.type === 'atrule' && node.name !== 'keyframes')
if (canRewriteSelector) {
root.walkRules((rule) => {
// Let's imagine you have the following structure:
//
// .foo {
// @apply bar;
// }
//
// @supports (a: b) {
// .bar {
// color: blue
// }
//
// .something-unrelated {}
// }
//
// In this case we want to apply `.bar` but it happens to be in
// an atrule node. We clone that node instead of the nested one
// because we still want that @supports rule to be there once we
// applied everything.
//
// However it happens to be that the `.something-unrelated` is
// also in that same shared @supports atrule. This is not good,
// and this should not be there. The good part is that this is
// a clone already and it can be safely removed. The question is
// how do we know we can remove it. Basically what we can do is
// match it against the applyCandidate that you want to apply. If
// it doesn't match the we can safely delete it.
//
// If we didn't do this, then the `replaceSelector` function
// would have replaced this with something that didn't exist and
// therefore it removed the selector altogether. In this specific
// case it would result in `{}` instead of `.something-unrelated {}`
if (!extractClasses(rule).some((candidate) => candidate === applyCandidate)) {
rule.remove()
return
}
if (canRewriteSelector) {
root.walkRules((rule) => {
rule.selector = replaceSelector(parent.selector, rule.selector, applyCandidate)
// Strip the important selector from the parent selector if at the beginning
let importantSelector =
typeof context.tailwindConfig.important === 'string'
? context.tailwindConfig.important
: null
rule.walkDecls((d) => {
d.important = meta.important || important
})
// We only want to move the "important" selector if this is a Tailwind-generated utility
// We do *not* want to do this for user CSS that happens to be structured the same
let isGenerated = parent.raws.tailwind !== undefined
let parentSelector =
isGenerated && importantSelector && parent.selector.indexOf(importantSelector) === 0
? parent.selector.slice(importantSelector.length)
: parent.selector
// 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 = applyImportantSelector(rule.selector, importantSelector)
}
rule.walkDecls((d) => {
d.important = meta.important || important
})
}
// Insert it
siblings.push([
// Ensure that when we are sorting, that we take the layer order into account
{ ...meta, sort: meta.sort | context.layerOrder[meta.layer] },
root.nodes[0],
])
// 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()
})
}
}
// Inject the rules, sorted, correctly
let nodes = siblings.sort(([a], [z]) => bigSign(a.sort - z.sort)).map((s) => s[1])
// It could be that the node we were inserted was removed because the class didn't match
// If that was the *only* rule in the parent, then we have nothing add so we skip it
if (!root.nodes[0]) {
continue
}
// console.log(parent)
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
parent.after(nodes)
// Insert it
siblings.push([meta.sort, root.nodes[0]])
}
}
for (let apply of applies) {
// If there are left-over declarations, just remove the @apply
if (apply.parent.nodes.length > 1) {
apply.remove()
} else {
// The node is empty, drop the full node
apply.parent.remove()
}
// Inject the rules, sorted, correctly
let nodes = context.offsets.sort(siblings).map((s) => s[1])
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
parent.after(nodes)
}
for (let apply of applies) {
// If there are left-over declarations, just remove the @apply
if (apply.parent.nodes.length > 1) {
apply.remove()
} else {
// The node is empty, drop the full node
apply.parent.remove()
}
}
// Do it again, in case we have other `@apply` rules
processApply(root, context)
}
// Do it again, in case we have other `@apply` rules
processApply(root, context, localCache)
}

@@ -252,5 +636,7 @@

return (root) => {
partitionApplyParents(root)
processApply(root, context)
// Build a cache of the user's CSS so we can use it to resolve classes used by @apply
let localCache = lazyCache(() => buildLocalApplyCache(root, context))
processApply(root, context, localCache)
}
}

@@ -1,29 +0,13 @@

import LRU from 'quick-lru'
import fs from 'fs'
import LRU from '@alloc/quick-lru'
import * as sharedState from './sharedState'
import { generateRules } from './generateRules'
import bigSign from '../util/bigSign'
import log from '../util/log'
import cloneNodes from '../util/cloneNodes'
import { defaultExtractor } from './defaultExtractor'
let env = sharedState.env
const PATTERNS = [
/([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif]
/([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source, // font-["some_font",sans-serif]
/([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')]
/([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")]
/([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']`
/([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]`
/([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50`
/([^<>"'`\s]*[^"'`\s:])/.source, // `px-1.5`, `uppercase` but not `uppercase:`].join('|')
].join('|')
const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g')
const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g
const builtInExtractors = {
DEFAULT: (content) => {
let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || []
let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || []
return [...broadMatches, ...innerMatches]
},
DEFAULT: defaultExtractor,
}

@@ -36,4 +20,4 @@

function getExtractor(tailwindConfig, fileExtension) {
let extractors = tailwindConfig.content.extract
function getExtractor(context, fileExtension) {
let extractors = context.tailwindConfig.content.extract

@@ -44,3 +28,3 @@ return (

builtInExtractors[fileExtension] ||
builtInExtractors.DEFAULT
builtInExtractors.DEFAULT(context)
)

@@ -95,47 +79,20 @@ }

/**
*
* @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
* @param {*} context
*/
function buildStylesheet(rules, context) {
let sortedRules = rules.sort(([a], [z]) => bigSign(a - z))
let sortedRules = context.offsets.sort(rules)
let returnValue = {
base: new Set(),
defaults: new Set(),
components: new Set(),
utilities: new Set(),
variants: new Set(),
// All the CSS that is not Tailwind related can be put in this bucket. This
// will make it easier to later use this information when we want to
// `@apply` for example. The main reason we do this here is because we
// still need to make sure the order is correct. Last but not least, we
// will make sure to always re-inject this section into the css, even if
// certain rules were not used. This means that it will look like a no-op
// from the user's perspective, but we gathered all the useful information
// we need.
user: new Set(),
}
for (let [sort, rule] of sortedRules) {
if (sort >= context.minimumScreen) {
returnValue.variants.add(rule)
continue
}
if (sort & context.layerOrder.base) {
returnValue.base.add(rule)
continue
}
if (sort & context.layerOrder.components) {
returnValue.components.add(rule)
continue
}
if (sort & context.layerOrder.utilities) {
returnValue.utilities.add(rule)
continue
}
if (sort & context.layerOrder.user) {
returnValue.user.add(rule)
continue
}
returnValue[sort.layer].add(rule)
}

@@ -147,3 +104,3 @@

export default function expandTailwindAtRules(context) {
return (root) => {
return async (root) => {
let layerNodes = {

@@ -156,9 +113,11 @@ base: null,

// Make sure this file contains Tailwind directives. If not, we can save
// a lot of work and bail early. Also we don't have to register our touch
// file as a dependency since the output of this CSS does not depend on
// the source of any templates. Think Vue <style> blocks for example.
root.walkAtRules('tailwind', (rule) => {
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule
root.walkAtRules((rule) => {
// Make sure this file contains Tailwind directives. If not, we can save
// a lot of work and bail early. Also we don't have to register our touch
// file as a dependency since the output of this CSS does not depend on
// the source of any templates. Think Vue <style> blocks for example.
if (rule.name === 'tailwind') {
if (Object.keys(layerNodes).includes(rule.params)) {
layerNodes[rule.params] = rule
}
}

@@ -174,3 +133,3 @@ })

// Find potential rules in changed files
let candidates = new Set(['*'])
let candidates = new Set([...(context.candidates ?? []), sharedState.NOT_ON_DEMAND])
let seen = new Set()

@@ -180,8 +139,25 @@

for (let { content, extension } of context.changedContent) {
let transformer = getTransformer(context.tailwindConfig, extension)
let extractor = getExtractor(context.tailwindConfig, extension)
getClassCandidates(transformer(content), extractor, candidates, seen)
/** @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)
})
)
}
env.DEBUG && console.timeEnd('Reading changed files')
// ---

@@ -193,3 +169,12 @@

env.DEBUG && console.time('Generate rules')
let rules = generateRules(candidates, context)
env.DEBUG && console.time('Sorting candidates')
let sortedCandidates = 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')

@@ -200,6 +185,2 @@

if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
for (let rule of rules) {
context.ruleCache.add(rule)
}
context.stylesheetCache = buildStylesheet([...context.ruleCache], context)

@@ -210,2 +191,3 @@ }

let {
defaults: defaultNodes,
base: baseNodes,

@@ -222,3 +204,7 @@ components: componentNodes,

if (layerNodes.base) {
layerNodes.base.before(cloneNodes([...baseNodes], layerNodes.base.source))
layerNodes.base.before(
cloneNodes([...baseNodes, ...defaultNodes], layerNodes.base.source, {
layer: 'base',
})
)
layerNodes.base.remove()

@@ -228,3 +214,7 @@ }

if (layerNodes.components) {
layerNodes.components.before(cloneNodes([...componentNodes], layerNodes.components.source))
layerNodes.components.before(
cloneNodes([...componentNodes], layerNodes.components.source, {
layer: 'components',
})
)
layerNodes.components.remove()

@@ -234,13 +224,55 @@ }

if (layerNodes.utilities) {
layerNodes.utilities.before(cloneNodes([...utilityNodes], layerNodes.utilities.source))
layerNodes.utilities.before(
cloneNodes([...utilityNodes], layerNodes.utilities.source, {
layer: 'utilities',
})
)
layerNodes.utilities.remove()
}
// We do post-filtering to not alter the emitted order of the variants
const variantNodes = Array.from(screenNodes).filter((node) => {
const parentLayer = node.raws.tailwind?.parentLayer
if (parentLayer === 'components') {
return layerNodes.components !== null
}
if (parentLayer === 'utilities') {
return layerNodes.utilities !== null
}
return true
})
if (layerNodes.variants) {
layerNodes.variants.before(cloneNodes([...screenNodes], layerNodes.variants.source))
layerNodes.variants.before(
cloneNodes(variantNodes, layerNodes.variants.source, {
layer: 'variants',
})
)
layerNodes.variants.remove()
} else {
root.append(cloneNodes([...screenNodes], root.source))
} else if (variantNodes.length > 0) {
root.append(
cloneNodes(variantNodes, root.source, {
layer: 'variants',
})
)
}
// 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
const hasUtilityVariants = variantNodes.some(
(node) => node.raws.tailwind?.parentLayer === 'utilities'
)
if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
log.warn('content-problems', [
'No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.',
'https://tailwindcss.com/docs/content-configuration',
])
}
// ---

@@ -247,0 +279,0 @@

@@ -6,4 +6,17 @@ import postcss from 'postcss'

import prefixSelector from '../util/prefixSelector'
import { updateAllClasses } from '../util/pluginUtils'
import { updateAllClasses, getMatchingTypes } from '../util/pluginUtils'
import log from '../util/log'
import * as sharedState from './sharedState'
import {
formatVariantSelector,
finalizeSelector,
eliminateIrrelevantSelectors,
} from '../util/formatVariantSelector'
import { asClass } from '../util/nameClass'
import { normalize } from '../util/dataTypes'
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'

@@ -14,3 +27,3 @@ let classNameParser = selectorParser((selectors) => {

function getClassNameFromSelector(selector) {
export function getClassNameFromSelector(selector) {
return classNameParser.transformSync(selector)

@@ -26,29 +39,45 @@ }

// ['grid', 'cols-[[linename],1fr,auto]']
function* candidatePermutations(candidate, lastIndex = Infinity) {
if (lastIndex < 0) {
return
}
function* candidatePermutations(candidate) {
let lastIndex = Infinity
let dashIdx
while (lastIndex >= 0) {
let dashIdx
let wasSlash = false
if (lastIndex === Infinity && candidate.endsWith(']')) {
let bracketIdx = candidate.indexOf('[')
if (lastIndex === Infinity && candidate.endsWith(']')) {
let bracketIdx = candidate.indexOf('[')
// If character before `[` isn't a dash or a slash, this isn't a dynamic class
// eg. string[]
dashIdx = ['-', '/'].includes(candidate[bracketIdx - 1]) ? bracketIdx - 1 : -1
} else {
dashIdx = candidate.lastIndexOf('-', lastIndex)
}
// If character before `[` isn't a dash or a slash, this isn't a dynamic class
// eg. string[]
if (candidate[bracketIdx - 1] === '-') {
dashIdx = bracketIdx - 1
} else if (candidate[bracketIdx - 1] === '/') {
dashIdx = bracketIdx - 1
wasSlash = true
} else {
dashIdx = -1
}
} else if (lastIndex === Infinity && candidate.includes('/')) {
dashIdx = candidate.lastIndexOf('/')
wasSlash = true
} else {
dashIdx = candidate.lastIndexOf('-', lastIndex)
}
if (dashIdx < 0) {
return
}
if (dashIdx < 0) {
break
}
let prefix = candidate.slice(0, dashIdx)
let modifier = candidate.slice(dashIdx + 1)
let prefix = candidate.slice(0, dashIdx)
let modifier = candidate.slice(wasSlash ? dashIdx : dashIdx + 1)
yield [prefix, modifier]
lastIndex = dashIdx - 1
yield* candidatePermutations(candidate, dashIdx - 1)
// TODO: This feels a bit hacky
if (prefix === '' || modifier === '/') {
continue
}
yield [prefix, modifier]
}
}

@@ -65,5 +94,19 @@

let container = postcss.root({ nodes: [match[1].clone()] })
let classCandidate = match[1].raws.tailwind.classCandidate
container.walkRules((r) => {
r.selector = prefixSelector(context.tailwindConfig.prefix, r.selector)
// If this is a negative utility with a dash *before* the prefix we
// have to ensure that the generated selector matches the candidate
// Not doing this will cause `-tw-top-1` to generate the class `.tw--top-1`
// The disconnect between candidate <-> class can cause @apply to hard crash.
let shouldPrependNegative = classCandidate.startsWith('-')
r.selector = prefixSelector(
context.tailwindConfig.prefix,
r.selector,
shouldPrependNegative
)
})
match[1] = container.nodes[0]

@@ -76,16 +119,38 @@ }

function applyImportant(matches) {
function applyImportant(matches, classCandidate) {
if (matches.length === 0) {
return matches
}
let result = []
function isInKeyframes(rule) {
return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes'
}
for (let [meta, rule] of matches) {
let container = postcss.root({ nodes: [rule.clone()] })
container.walkRules((r) => {
r.selector = updateAllClasses(r.selector, (className) => {
return `!${className}`
})
// Declarations inside keyframes cannot be marked as important
// They will be ignored by the browser
if (isInKeyframes(r)) {
return
}
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]])

@@ -111,12 +176,107 @@ }

/** @type {{modifier: string | null, value: string | null}} */
let args = { modifier: null, value: sharedState.NONE }
// Retrieve "modifier"
{
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')) {
return []
}
}
}
// Retrieve "arbitrary value"
if (variant.endsWith(']') && !variant.startsWith('[')) {
// We either have:
// @[200px]
// group-[:hover]
//
// But we don't want:
// @-[200px] (`-` is incorrect)
// group[:hover] (`-` is missing)
let match = /(.)(-?)\[(.*)\]/g.exec(variant)
if (match) {
let [, char, separator, value] = match
// @-[200px] case
if (char === '@' && separator === '-') return []
// group[:hover] case
if (char !== '@' && separator === '') return []
variant = variant.replace(`${separator}[${value}]`, '')
args.value = value
}
}
// Register arbitrary variants
if (isArbitraryValue(variant) && !context.variantMap.has(variant)) {
let sort = context.offsets.recordVariant(variant)
let selector = normalize(variant.slice(1, -1))
let selectors = splitAtTopLevelOnly(selector, ',')
// We do not support multiple selectors for arbitrary variants
if (selectors.length > 1) {
return []
}
if (!selectors.every(isValidVariantFormatString)) {
return []
}
let records = selectors.map((sel, idx) => [
context.offsets.applyParallelOffset(sort, idx),
parseVariant(sel.trim()),
])
context.variantMap.set(variant, records)
}
if (context.variantMap.has(variant)) {
let variantFunctionTuples = context.variantMap.get(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) {
// Don't generate variants for user css
if (meta.layer === 'user') {
continue
}
let container = postcss.root({ nodes: [rule.clone()] })
for (let [variantSort, variantFunction] of variantFunctionTuples) {
let clone = container.clone()
for (let [variantSort, variantFunction, containerFromArray] of variantFunctionTuples) {
let clone = (containerFromArray ?? container).clone()
let collectedFormats = []
function prepareBackup() {
// Already prepared, chicken out
if (clone.raws.neededBackup) {
return
}
clone.raws.neededBackup = true
clone.walkRules((rule) => (rule.raws.originalSelector = rule.selector))
}
function modifySelectors(modifierFunction) {
prepareBackup()
clone.each((rule) => {

@@ -136,2 +296,3 @@ if (rule.type !== 'rule') {

})
return clone

@@ -141,7 +302,53 @@ }

let ruleWithVariant = variantFunction({
container: clone,
// Public API
get container() {
prepareBackup()
return clone
},
separator: context.tailwindConfig.separator,
modifySelectors,
// Private API for now
wrap(wrapper) {
let nodes = clone.nodes
clone.removeAll()
wrapper.append(nodes)
clone.append(wrapper)
},
format(selectorFormat) {
collectedFormats.push({
format: selectorFormat,
respectPrefix,
})
},
args,
})
// It can happen that a list of format strings is returned from within the function. In that
// case, we have to process them as well. We can use the existing `variantSort`.
if (Array.isArray(ruleWithVariant)) {
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
// currently looping over. However, you can also think of it like a processing queue
// where you keep handling jobs until everything is done and each job can queue more
// jobs if needed.
variantFunctionTuples.push([
context.offsets.applyParallelOffset(variantSort, idx),
variantFunction,
// If the clone has been modified we have to pass that back
// though so each rule can use the modified container
clone.clone(),
])
}
continue
}
if (typeof ruleWithVariant === 'string') {
collectedFormats.push({
format: ruleWithVariant,
respectPrefix,
})
}
if (ruleWithVariant === null) {

@@ -151,3 +358,62 @@ continue

let withOffset = [{ ...meta, sort: variantSort | meta.sort }, clone.nodes[0]]
// We had to backup selectors, therefore we assume that somebody touched
// `container` or `modifySelectors`. Let's see if they did, so that we
// can restore the selectors, and collect the format strings.
if (clone.raws.neededBackup) {
delete clone.raws.neededBackup
clone.walkRules((rule) => {
let before = rule.raws.originalSelector
if (!before) return
delete rule.raws.originalSelector
if (before === rule.selector) return // No mutation happened
let modified = rule.selector
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = selectorParser((selectors) => {
selectors.walkClasses((classNode) => {
classNode.value = `${variant}${context.tailwindConfig.separator}${classNode.value}`
})
}).processSync(before)
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
collectedFormats.push({
format: modified.replace(rebuiltBase, '&'),
respectPrefix,
})
rule.selector = before
})
}
// This tracks the originating layer for the variant
// For example:
// .sm:underline {} is a variant of something in the utilities layer
// .sm:container {} is a variant of the container component
clone.nodes[0].raws.tailwind = { ...clone.nodes[0].raws.tailwind, parentLayer: meta.layer }
let withOffset = [
{
...meta,
sort: context.offsets.applyVariantOffset(
meta.sort,
variantSort,
Object.assign(args, context.variantOptions.get(variant))
),
collectedFormats: (meta.collectedFormats ?? []).concat(collectedFormats),
},
clone.nodes[0],
]
result.push(withOffset)

@@ -182,2 +448,92 @@ }

const IS_VALID_PROPERTY_NAME = /^[a-z_-]/
function isValidPropName(name) {
return IS_VALID_PROPERTY_NAME.test(name)
}
/**
* @param {string} declaration
* @returns {boolean}
*/
function looksLikeUri(declaration) {
// Quick bailout for obvious non-urls
// This doesn't support schemes that don't use a leading // but that's unlikely to be a problem
if (!declaration.includes('://')) {
return false
}
try {
const url = new URL(declaration)
return url.scheme !== '' && url.host !== ''
} catch (err) {
// Definitely not a valid url
return false
}
}
function isParsableNode(node) {
let isParsable = true
node.walkDecls((decl) => {
if (!isParsableCssValue(decl.prop, decl.value)) {
isParsable = false
return false
}
})
return isParsable
}
function isParsableCssValue(property, value) {
// We don't want to to treat [https://example.com] as a custom property
// Even though, according to the CSS grammar, it's a totally valid CSS declaration
// So we short-circuit here by checking if the custom property looks like a url
if (looksLikeUri(`${property}:${value}`)) {
return false
}
try {
postcss.parse(`a{${property}:${value}}`).toResult()
return true
} catch (err) {
return false
}
}
function extractArbitraryProperty(classCandidate, context) {
let [, property, value] = classCandidate.match(/^\[([a-zA-Z0-9-_]+):(\S+)\]$/) ?? []
if (value === undefined) {
return null
}
if (!isValidPropName(property)) {
return null
}
if (!isValidArbitraryValue(value)) {
return null
}
let normalized = normalize(value, { property })
if (!isParsableCssValue(property, normalized)) {
return null
}
let sort = context.offsets.arbitraryProperty(classCandidate)
return [
[
{ sort, layer: 'utilities', options: { respectImportant: true } },
() => ({
[asClass(classCandidate)]: {
[property]: normalized,
},
}),
],
]
}
function* resolveMatchedPlugins(classCandidate, context) {

@@ -188,8 +544,19 @@ if (context.candidateRuleMap.has(classCandidate)) {

yield* (function* (arbitraryPropertyRule) {
if (arbitraryPropertyRule !== null) {
yield [arbitraryPropertyRule, 'DEFAULT']
}
})(extractArbitraryProperty(classCandidate, context))
let candidatePrefix = classCandidate
let negative = false
const twConfigPrefix = context.tailwindConfig.prefix || ''
const twConfigPrefix = context.tailwindConfig.prefix
const twConfigPrefixLen = twConfigPrefix.length
if (candidatePrefix[twConfigPrefixLen] === '-') {
const hasMatchingPrefix =
candidatePrefix.startsWith(twConfigPrefix) || candidatePrefix.startsWith(`-${twConfigPrefix}`)
if (candidatePrefix[twConfigPrefixLen] === '-' && hasMatchingPrefix) {
negative = true

@@ -206,3 +573,2 @@ candidatePrefix = twConfigPrefix + candidatePrefix.slice(twConfigPrefixLen + 1)

yield [context.candidateRuleMap.get(prefix), negative ? `-${modifier}` : modifier]
return
}

@@ -213,5 +579,21 @@ }

function splitWithSeparator(input, separator) {
return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'))
if (input === sharedState.NOT_ON_DEMAND) {
return [sharedState.NOT_ON_DEMAND]
}
return splitAtTopLevelOnly(input, separator)
}
function* recordCandidates(matches, classCandidate) {
for (const match of matches) {
match[1].raws.tailwind = {
...match[1].raws.tailwind,
classCandidate,
preserveSource: match[0].options?.preserveSource ?? false,
}
yield match
}
}
function* resolveMatches(candidate, context) {

@@ -267,3 +649,15 @@ let separator = context.tailwindConfig.separator

if (matchesPerPlugin.length > 0) {
typesByMatches.set(matchesPerPlugin, sort.options?.type)
let matchingTypes = Array.from(
getMatchingTypes(
sort.options?.types ?? [],
modifier,
sort.options ?? {},
context.tailwindConfig
)
).map(([_, type]) => type)
if (matchingTypes.length > 0) {
typesByMatches.set(matchesPerPlugin, matchingTypes)
}
matches.push(matchesPerPlugin)

@@ -273,62 +667,123 @@ }

// Only keep the result of the very first plugin if we are dealing with
// arbitrary values, to protect against ambiguity.
if (isArbitraryValue(modifier) && matches.length > 1) {
let typesPerPlugin = matches.map((match) => new Set([...(typesByMatches.get(match) ?? [])]))
if (isArbitraryValue(modifier)) {
if (matches.length > 1) {
// Partition plugins in 2 categories so that we can start searching in the plugins that
// don't have `any` as a type first.
let [withAny, withoutAny] = matches.reduce(
(group, plugin) => {
let hasAnyType = plugin.some(([{ options }]) =>
options.types.some(({ type }) => type === 'any')
)
// Remove duplicates, so that we can detect proper unique types for each plugin.
for (let pluginTypes of typesPerPlugin) {
for (let type of pluginTypes) {
let removeFromOwnGroup = false
if (hasAnyType) {
group[0].push(plugin)
} else {
group[1].push(plugin)
}
return group
},
[[], []]
)
for (let otherGroup of typesPerPlugin) {
if (pluginTypes === otherGroup) continue
function findFallback(matches) {
// If only a single plugin matches, let's take that one
if (matches.length === 1) {
return matches[0]
}
if (otherGroup.has(type)) {
otherGroup.delete(type)
removeFromOwnGroup = true
// Otherwise, find the plugin that creates a valid rule given the arbitrary value, and
// also has the correct type which preferOnConflicts the plugin in case of clashes.
return matches.find((rules) => {
let matchingTypes = typesByMatches.get(rules)
return rules.some(([{ options }, rule]) => {
if (!isParsableNode(rule)) {
return false
}
return options.types.some(
({ type, preferOnConflict }) => matchingTypes.includes(type) && preferOnConflict
)
})
})
}
// Try to find a fallback plugin, because we already know that multiple plugins matched for
// the given arbitrary value.
let fallback = findFallback(withoutAny) ?? findFallback(withAny)
if (fallback) {
matches = [fallback]
}
// We couldn't find a fallback plugin which means that there are now multiple plugins that
// generated css for the current candidate. This means that the result is ambiguous and this
// should not happen. We won't generate anything right now, so let's report this to the user
// by logging some options about what they can do.
else {
let typesPerPlugin = matches.map(
(match) => new Set([...(typesByMatches.get(match) ?? [])])
)
// Remove duplicates, so that we can detect proper unique types for each plugin.
for (let pluginTypes of typesPerPlugin) {
for (let type of pluginTypes) {
let removeFromOwnGroup = false
for (let otherGroup of typesPerPlugin) {
if (pluginTypes === otherGroup) continue
if (otherGroup.has(type)) {
otherGroup.delete(type)
removeFromOwnGroup = true
}
}
if (removeFromOwnGroup) pluginTypes.delete(type)
}
}
if (removeFromOwnGroup) pluginTypes.delete(type)
}
}
let messages = []
let messages = []
for (let [idx, group] of typesPerPlugin.entries()) {
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')
for (let [idx, group] of typesPerPlugin.entries()) {
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('[', `[${type}:`)}\` for \`${rules.trim()}\``
)
break
}
}
messages.push(` Use \`${candidate.replace('[', `[${type}:`)}\` for \`${rules.trim()}\``)
break
log.warn([
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
...messages,
`If this is content and not a class, replace it with \`${candidate
.replace('[', '&lsqb;')
.replace(']', '&rsqb;')}\` to silence this warning.`,
])
continue
}
}
log.warn([
`The class \`${candidate}\` is ambiguous and matches multiple utilities.`,
...messages,
`If this is content and not a class, replace it with \`${candidate
.replace('[', '&lsqb;')
.replace(']', '&rsqb;')}\` to silence this warning.`,
])
continue
matches = matches.map((list) => list.filter((match) => isParsableNode(match[1])))
}
matches = applyPrefix(matches.flat(), context)
matches = matches.flat()
matches = Array.from(recordCandidates(matches, classCandidate))
matches = applyPrefix(matches, context)
if (important) {
matches = applyImportant(matches, context)
matches = applyImportant(matches, classCandidate)
}

@@ -341,2 +796,14 @@

for (let match of matches) {
match[1].raws.tailwind = { ...match[1].raws.tailwind, candidate }
// Apply final format selector
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
}
yield match

@@ -347,2 +814,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) {

@@ -352,4 +889,33 @@ return rule.parent && rule.parent.type === 'atrule' && rule.parent.name === 'keyframes'

function generateRules(candidates, context) {
function getImportantStrategy(important) {
if (important === true) {
return (rule) => {
if (inKeyframes(rule)) {
return
}
rule.walkDecls((d) => {
if (d.parent.type === 'rule' && !inKeyframes(d.parent)) {
d.important = true
}
})
}
}
if (typeof important === 'string') {
return (rule) => {
if (inKeyframes(rule)) {
return
}
rule.selectors = rule.selectors.map((selector) => {
return applyImportantSelector(selector, important)
})
}
}
}
function generateRules(candidates, context, isSorting = false) {
let allRules = []
let strategy = getImportantStrategy(context.tailwindConfig.important)

@@ -361,4 +927,4 @@ for (let candidate of candidates) {

if (context.classCache.has(candidate)) {
allRules.push(context.classCache.get(candidate))
if (context.candidateRuleCache.has(candidate)) {
allRules = allRules.concat(Array.from(context.candidateRuleCache.get(candidate)))
continue

@@ -375,29 +941,25 @@ }

context.classCache.set(candidate, matches)
allRules.push(matches)
}
return allRules.flat(1).map(([{ sort, layer, options }, rule]) => {
if (options.respectImportant) {
if (context.tailwindConfig.important === true) {
rule.walkDecls((d) => {
if (d.parent.type === 'rule' && !inKeyframes(d.parent)) {
d.important = true
}
})
} else if (typeof context.tailwindConfig.important === 'string') {
let rules = context.candidateRuleCache.get(candidate) ?? new Set()
context.candidateRuleCache.set(candidate, rules)
for (const match of matches) {
let [{ sort, options }, rule] = match
if (options.respectImportant && strategy) {
let container = postcss.root({ nodes: [rule.clone()] })
container.walkRules((r) => {
if (inKeyframes(r)) {
return
}
r.selectors = r.selectors.map((selector) => {
return `${context.tailwindConfig.important} ${selector}`
})
})
container.walkRules(strategy)
rule = container.nodes[0]
}
// 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)
context.ruleCache.add(newEntry)
allRules.push(newEntry)
}
return [sort | context.layerOrder[layer], rule]
})
}
return allRules
}

@@ -404,0 +966,0 @@

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())
)
}

@@ -6,4 +6,9 @@ import log from '../util/log'

let layerDirectives = new Set()
let applyDirectives = new Set()
root.walkAtRules((atRule) => {
if (atRule.name === 'apply') {
applyDirectives.add(atRule)
}
if (atRule.name === 'import') {

@@ -48,2 +53,3 @@ if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") {

`Use \`@layer utilities\` or \`@layer components\` instead.`,
'https://tailwindcss.com/docs/upgrade-guide#replace-variants-with-layer',
])

@@ -79,3 +85,3 @@ }

return tailwindDirectives
return { tailwindDirectives, applyDirectives }
}

@@ -74,2 +74,4 @@ import postcss from 'postcss'

let variableNodeMap = new Map()
/** @type {Set<import('postcss').AtRule>} */
let universals = new Set()

@@ -93,31 +95,75 @@

for (let universal of universals) {
let selectors = new Set()
if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
for (let universal of universals) {
/** @type {Map<string, Set<string>>} */
let selectorGroups = new Map()
let rules = variableNodeMap.get(universal.params) ?? []
let rules = variableNodeMap.get(universal.params) ?? []
for (let rule of rules) {
for (let selector of extractElementSelector(rule.selector)) {
selectors.add(selector)
for (let rule of rules) {
for (let selector of extractElementSelector(rule.selector)) {
// If selector contains a vendor prefix after a pseudo element or class,
// we consider them separately because merging the declarations into
// a single rule will cause browsers that do not understand the
// vendor prefix to throw out the whole rule
// Additionally if a selector contains `:has` we also consider
// it separately because FF only recently gained support for it
let selectorGroupName =
selector.includes(':-') || selector.includes('::-') || selector.includes(':has')
? selector
: '__DEFAULT__'
let selectors = selectorGroups.get(selectorGroupName) ?? new Set()
selectorGroups.set(selectorGroupName, selectors)
selectors.add(selector)
}
}
}
if (selectors.size === 0) {
if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
if (selectorGroups.size === 0) {
universal.remove()
continue
}
for (let [, selectors] of selectorGroups) {
let universalRule = postcss.rule({
source: universal.source,
})
universalRule.selectors = [...selectors]
universalRule.append(universal.nodes.map((node) => node.clone()))
universal.before(universalRule)
}
}
universal.remove()
continue
}
} else if (universals.size) {
let universalRule = postcss.rule({
selectors: ['*', '::before', '::after'],
})
let universalRule = postcss.rule()
for (let universal of universals) {
universalRule.append(universal.nodes)
if (flagEnabled(tailwindConfig, 'optimizeUniversalDefaults')) {
universalRule.selectors = [...selectors]
} else {
universalRule.selectors = ['*', '::before', '::after']
if (!universalRule.parent) {
universal.before(universalRule)
}
if (!universalRule.source) {
universalRule.source = universal.source
}
universal.remove()
}
universalRule.append(universal.nodes)
universal.before(universalRule)
universal.remove()
let backdropRule = universalRule.clone({
selectors: ['::backdrop'],
})
universalRule.after(backdropRule)
}
}
}

@@ -14,3 +14,2 @@ import fs from 'fs'

import { coerceValue } from '../util/pluginUtils'
import bigSign from '../util/bigSign'
import { variantPlugins, corePlugins } from '../corePlugins'

@@ -22,3 +21,87 @@ import * as sharedState from './sharedState'

import negateValue from '../util/negateValue'
import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPropertyValue'
import { generateRules, getClassNameFromSelector } from './generateRules'
import { hasContentChanged } from './cacheInvalidation.js'
import { Offsets } from './offsets.js'
import { flagEnabled } from '../featureFlags.js'
import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector'
export const INTERNAL_FEATURES = Symbol()
const VARIANT_TYPES = {
AddVariant: Symbol.for('ADD_VARIANT'),
MatchVariant: Symbol.for('MATCH_VARIANT'),
}
const VARIANT_INFO = {
Base: 1 << 0,
Dynamic: 1 << 1,
}
function prefix(context, selector) {
let prefix = context.tailwindConfig.prefix
return typeof prefix === 'function' ? prefix(selector) : prefix + selector
}
function normalizeOptionTypes({ type = 'any', ...options }) {
let types = [].concat(type)
return {
...options,
types: types.map((type) => {
if (Array.isArray(type)) {
return { type: type[0], ...type[1] }
}
return { type, preferOnConflict: false }
}),
}
}
function parseVariantFormatString(input) {
/** @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 === '}') {
// Nested rule: end
if (--depth < 0) {
throw new Error(`Your { and } are unbalanced.`)
}
parts.push(current.trim())
current = ''
} else {
// Normal character
current += char
}
}
if (current.length > 0) {
parts.push(current.trim())
}
parts = parts.filter((part) => part !== '')
return parts
}
function insertInto(list, value, { before = [] } = {}) {

@@ -53,8 +136,14 @@ before = [].concat(before)

function getClasses(selector) {
function getClasses(selector, mutate) {
let parser = selectorParser((selectors) => {
let allClasses = []
if (mutate) {
mutate(selectors)
}
selectors.walkClasses((classNode) => {
allClasses.push(classNode.value)
})
return allClasses

@@ -65,20 +154,45 @@ })

function extractCandidates(node) {
/**
* 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 = []
if (node.type === 'rule') {
for (let selector of node.selectors) {
let classCandidates = getClasses(selector)
// At least one of the selectors contains non-"on-demandable" candidates.
if (classCandidates.length === 0) return []
// 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))
}
classes = [...classes, ...classCandidates]
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
}
return classes
for (let classCandidate of classCandidates) {
classes.push(classCandidate)
}
}
if (node.type === 'atrule') {
node.walkRules((rule) => {
classes = [...classes, ...rule.selectors.flatMap((selector) => getClasses(selector))]
})
if (depth === 0) {
return [state.containsNonOnDemandable || classes.length === 0, classes]
}

@@ -92,9 +206,12 @@

let nodeMap = new Map()
let candidates = extractCandidates(node)
let [containsNonOnDemandableSelectors, candidates] = extractCandidates(node)
// If this isn't "on-demandable", assign it a universal candidate.
if (candidates.length === 0) {
return [['*', node]]
// If this isn't "on-demandable", assign it a universal candidate to always include it.
if (containsNonOnDemandableSelectors) {
candidates.unshift(sharedState.NOT_ON_DEMAND)
}
// However, it could be that it also contains "on-demandable" candidates.
// E.g.: `span, .foo {}`, in that case it should still be possible to use
// `@apply foo` for example.
return candidates.map((c) => {

@@ -109,60 +226,37 @@ if (!nodeMap.has(node)) {

let matchingBrackets = new Map([
['{', '}'],
['[', ']'],
['(', ')'],
])
let inverseMatchingBrackets = new Map(
Array.from(matchingBrackets.entries()).map(([k, v]) => [v, k])
)
export function isValidVariantFormatString(format) {
return format.startsWith('@') || format.includes('&')
}
let quotes = new Set(['"', "'", '`'])
export function parseVariant(variant) {
variant = variant
.replace(/\n+/g, '')
.replace(/\s{1,}/g, ' ')
.trim()
// Arbitrary values must contain balanced brackets (), [] and {}. Escaped
// values don't count, and brackets inside quotes also don't count.
//
// E.g.: w-[this-is]w-[weird-and-invalid]
// E.g.: w-[this-is\\]w-\\[weird-but-valid]
// E.g.: content-['this-is-also-valid]-weirdly-enough']
function isValidArbitraryValue(value) {
let stack = []
let inQuotes = false
let fns = parseVariantFormatString(variant)
.map((str) => {
if (!str.startsWith('@')) {
return ({ format }) => format(str)
}
for (let i = 0; i < value.length; i++) {
let char = value[i]
let [, name, params] = /@(\S*)( .+|[({].*)?/g.exec(str)
return ({ wrap }) => wrap(postcss.atRule({ name, params: params?.trim() ?? '' }))
})
.reverse()
// Non-escaped quotes allow us to "allow" anything in between
if (quotes.has(char) && value[i - 1] !== '\\') {
inQuotes = !inQuotes
return (api) => {
for (let fn of fns) {
fn(api)
}
if (inQuotes) continue
if (value[i - 1] === '\\') continue // Escaped
if (matchingBrackets.has(char)) {
stack.push(char)
} else if (inverseMatchingBrackets.has(char)) {
let inverse = inverseMatchingBrackets.get(char)
// Nothing to pop from, therefore it is unbalanced
if (stack.length <= 0) {
return false
}
// Popped value must match the inverse value, otherwise it is unbalanced
if (stack.pop() !== inverse) {
return false
}
}
}
// If there is still something on the stack, it is also unbalanced
if (stack.length > 0) {
return false
}
// All good, totally balanced!
return true
}
/**
*
* @param {any} tailwindConfig
* @param {any} context
* @param {object} param2
* @param {Offsets} param2.offsets
*/
function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offsets, classList }) {

@@ -178,4 +272,4 @@ function getConfigValue(path, defaultValue) {

function prefixIdentifier(identifier, options) {
if (identifier === '*') {
return '*'
if (identifier === sharedState.NOT_ON_DEMAND) {
return sharedState.NOT_ON_DEMAND
}

@@ -187,16 +281,13 @@

if (typeof context.tailwindConfig.prefix === 'function') {
return prefixSelector(context.tailwindConfig.prefix, `.${identifier}`).substr(1)
}
return context.tailwindConfig.prefix + identifier
}
return {
addVariant(variantName, variantFunctions, options = {}) {
variantFunctions = [].concat(variantFunctions)
function resolveThemeValue(path, defaultValue, opts = {}) {
let parts = toPath(path)
let value = getConfigValue(['theme', ...parts], defaultValue)
return transformThemeValue(parts[0])(value, opts)
}
insertInto(variantList, variantName, options)
variantMap.set(variantName, variantFunctions)
},
let variantIdentifier = 0
let api = {
postcss,

@@ -206,7 +297,3 @@ prefix: applyConfiguredPrefix,

config: getConfigValue,
theme(path, defaultValue) {
const [pathRoot, ...subPaths] = toPath(path)
const value = getConfigValue(['theme', pathRoot, ...subPaths], defaultValue)
return transformThemeValue(pathRoot)(value)
},
theme: resolveThemeValue,
corePlugins: (path) => {

@@ -223,17 +310,27 @@ if (Array.isArray(tailwindConfig.corePlugins)) {

},
addUserCss(userCss) {
for (let [identifier, rule] of withIdentifiers(userCss)) {
let offset = offsets.user++
addBase(base) {
for (let [identifier, rule] of withIdentifiers(base)) {
let prefixedIdentifier = prefixIdentifier(identifier, {})
let offset = offsets.create('base')
if (!context.candidateRuleMap.has(identifier)) {
context.candidateRuleMap.set(identifier, [])
if (!context.candidateRuleMap.has(prefixedIdentifier)) {
context.candidateRuleMap.set(prefixedIdentifier, [])
}
context.candidateRuleMap.get(identifier).push([{ sort: offset, layer: 'user' }, rule])
context.candidateRuleMap
.get(prefixedIdentifier)
.push([{ sort: offset, layer: 'base' }, rule])
}
},
addBase(base) {
for (let [identifier, rule] of withIdentifiers(base)) {
/**
* @param {string} group
* @param {Record<string, string | string[]>} declarations
*/
addDefaults(group, declarations) {
const groups = {
[`@defaults ${group}`]: declarations,
}
for (let [identifier, rule] of withIdentifiers(groups)) {
let prefixedIdentifier = prefixIdentifier(identifier, {})
let offset = offsets.base++

@@ -246,3 +343,3 @@ if (!context.candidateRuleMap.has(prefixedIdentifier)) {

.get(prefixedIdentifier)
.push([{ sort: offset, layer: 'base' }, rule])
.push([{ sort: offsets.create('defaults'), layer: 'defaults' }, rule])
}

@@ -252,2 +349,3 @@ },

let defaultOptions = {
preserveSource: false,
respectPrefix: true,

@@ -261,3 +359,2 @@ respectImportant: false,

let prefixedIdentifier = prefixIdentifier(identifier, options)
let offset = offsets.components++

@@ -272,3 +369,3 @@ classList.add(prefixedIdentifier)

.get(prefixedIdentifier)
.push([{ sort: offset, layer: 'components', options }, rule])
.push([{ sort: offsets.create('components'), layer: 'components', options }, rule])
}

@@ -278,2 +375,3 @@ },

let defaultOptions = {
preserveSource: false,
respectPrefix: true,

@@ -287,3 +385,2 @@ respectImportant: true,

let prefixedIdentifier = prefixIdentifier(identifier, options)
let offset = offsets.utilities++

@@ -298,3 +395,3 @@ classList.add(prefixedIdentifier)

.get(prefixedIdentifier)
.push([{ sort: offset, layer: 'utilities', options }, rule])
.push([{ sort: offsets.create('utilities'), layer: 'utilities', options }, rule])
}

@@ -306,7 +403,8 @@ },

respectImportant: true,
modifiers: false,
}
options = { ...defaultOptions, ...options }
options = normalizeOptionTypes({ ...defaultOptions, ...options })
let offset = offsets.utilities++
let offset = offsets.create('utilities')

@@ -320,5 +418,8 @@ for (let identifier in utilities) {

function wrapped(modifier, { isOnlyPlugin }) {
let { type = 'any' } = options
type = [].concat(type)
let [value, coercedType] = coerceValue(type, modifier, options, tailwindConfig)
let [value, coercedType, utilityModifier] = coerceValue(
options.types,
modifier,
options,
tailwindConfig
)

@@ -329,12 +430,36 @@ if (value === undefined) {

if (!type.includes(coercedType) && !isOnlyPlugin) {
return []
if (!options.types.some(({ type }) => type === coercedType)) {
if (isOnlyPlugin) {
log.warn([
`Unnecessary typehint \`${coercedType}\` in \`${identifier}-${modifier}\`.`,
`You can safely update it to \`${identifier}-${modifier.replace(
coercedType + ':',
''
)}\`.`,
])
} else {
return []
}
}
if (!isValidArbitraryValue(value)) {
if (!isSyntacticallyValidPropertyValue(value)) {
return []
}
let extras = {
get modifier() {
if (!options.modifiers) {
log.warn(`modifier-used-without-options-for-${identifier}`, [
'Your plugin must set `modifiers: true` in its options to support modifiers.',
])
}
return utilityModifier
},
}
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
let ruleSets = []
.concat(rule(value))
.concat(modifiersEnabled ? rule(value, extras) : rule(value))
.filter(Boolean)

@@ -361,7 +486,8 @@ .map((declaration) => ({

respectImportant: false,
modifiers: false,
}
options = { ...defaultOptions, ...options }
options = normalizeOptionTypes({ ...defaultOptions, ...options })
let offset = offsets.components++
let offset = offsets.create('components')

@@ -375,5 +501,8 @@ for (let identifier in components) {

function wrapped(modifier, { isOnlyPlugin }) {
let { type = 'any' } = options
type = [].concat(type)
let [value, coercedType] = coerceValue(type, modifier, options, tailwindConfig)
let [value, coercedType, utilityModifier] = coerceValue(
options.types,
modifier,
options,
tailwindConfig
)

@@ -384,3 +513,3 @@ if (value === undefined) {

if (!type.includes(coercedType)) {
if (!options.types.some(({ type }) => type === coercedType)) {
if (isOnlyPlugin) {

@@ -399,8 +528,22 @@ log.warn([

if (!isValidArbitraryValue(value)) {
if (!isSyntacticallyValidPropertyValue(value)) {
return []
}
let extras = {
get modifier() {
if (!options.modifiers) {
log.warn(`modifier-used-without-options-for-${identifier}`, [
'Your plugin must set `modifiers: true` in its options to support modifiers.',
])
}
return utilityModifier
},
}
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
let ruleSets = []
.concat(rule(value))
.concat(modifiersEnabled ? rule(value, extras) : rule(value))
.filter(Boolean)

@@ -423,3 +566,105 @@ .map((declaration) => ({

},
addVariant(variantName, variantFunctions, options = {}) {
variantFunctions = [].concat(variantFunctions).map((variantFunction) => {
if (typeof variantFunction !== 'string') {
// Safelist public API functions
return (api = {}) => {
let { args, modifySelectors, container, separator, wrap, format } = api
let result = variantFunction(
Object.assign(
{ modifySelectors, container, separator },
options.type === VARIANT_TYPES.MatchVariant && { args, wrap, format }
)
)
if (typeof result === 'string' && !isValidVariantFormatString(result)) {
throw new Error(
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
)
}
if (Array.isArray(result)) {
return result
.filter((variant) => typeof variant === 'string')
.map((variant) => parseVariant(variant))
}
// result may be undefined with legacy variants that use APIs like `modifySelectors`
// result may also be a postcss node if someone was returning the result from `modifySelectors`
return result && typeof result === 'string' && parseVariant(result)(api)
}
}
if (!isValidVariantFormatString(variantFunction)) {
throw new Error(
`Your custom variant \`${variantName}\` has an invalid format string. Make sure it's an at-rule or contains a \`&\` placeholder.`
)
}
return parseVariant(variantFunction)
})
insertInto(variantList, variantName, options)
variantMap.set(variantName, variantFunctions)
context.variantOptions.set(variantName, options)
},
matchVariant(variant, variantFn, options) {
// 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 = options?.id ?? ++variantIdentifier
let isSpecial = variant === '@'
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
for (let [key, value] of Object.entries(options?.values ?? {})) {
if (key === 'DEFAULT') continue
api.addVariant(
isSpecial ? `${variant}${key}` : `${variant}-${key}`,
({ args, container }) => {
return variantFn(
value,
modifiersEnabled ? { modifier: args?.modifier, container } : { container }
)
},
{
...options,
value,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Base,
}
)
}
let hasDefault = 'DEFAULT' in (options?.values ?? {})
api.addVariant(
variant,
({ args, container }) => {
if (args?.value === sharedState.NONE && !hasDefault) {
return null
}
return variantFn(
args?.value === sharedState.NONE
? options.values.DEFAULT
: // Falling back to args if it is a string, otherwise '' for older intellisense
// (JetBrains) plugins.
args?.value ?? (typeof args === 'string' ? args : ''),
modifiersEnabled ? { modifier: args?.modifier, container } : { container }
)
},
{
...options,
id,
type: VARIANT_TYPES.MatchVariant,
variantInfo: VARIANT_INFO.Dynamic,
}
)
},
}
return api
}

@@ -437,2 +682,3 @@

let changed = false
let mtimesToCommit = new Map()

@@ -445,3 +691,10 @@ for (let file of files) {

pathname = parsed.search ? pathname.replace(parsed.search, '') : pathname
let newModified = fs.statSync(decodeURIComponent(pathname)).mtimeMs
let newModified = fs.statSync(decodeURIComponent(pathname), { throwIfNoEntry: false })?.mtimeMs
if (!newModified) {
// It could happen that a file is passed in that doesn't exist. E.g.:
// postcss-cli will provide you a fake path when reading from stdin. This
// path then looks like /path-to-your-project/stdin In that case we just
// want to ignore it and don't track changes at all.
continue
}

@@ -452,6 +705,6 @@ if (!fileModifiedMap.has(file) || newModified > fileModifiedMap.get(file)) {

fileModifiedMap.set(file, newModified)
mtimesToCommit.set(file, newModified)
}
return changed
return [changed, mtimesToCommit]
}

@@ -493,3 +746,3 @@

layerPlugins.push(function ({ addComponents }) {
addComponents(node, { respectPrefix: false })
addComponents(node, { respectPrefix: false, preserveSource: true })
})

@@ -501,3 +754,3 @@ }

layerPlugins.push(function ({ addUtilities }) {
addUtilities(node, { respectPrefix: false })
addUtilities(node, { respectPrefix: false, preserveSource: true })
})

@@ -509,11 +762,2 @@ }

root.walkRules((rule) => {
// At this point it is safe to include all the left-over css from the
// user's css file. This is because the `@tailwind` and `@layer` directives
// will already be handled and will be removed from the css tree.
layerPlugins.push(function ({ addUserCss }) {
addUserCss(rule, { respectPrefix: false })
})
})
return layerPlugins

@@ -546,12 +790,42 @@ }

let beforeVariants = [
variantPlugins['childVariant'],
variantPlugins['pseudoElementVariants'],
variantPlugins['pseudoClassVariants'],
variantPlugins['hasVariants'],
variantPlugins['ariaVariants'],
variantPlugins['dataVariants'],
]
let afterVariants = [
variantPlugins['supportsVariants'],
variantPlugins['reducedMotionVariants'],
variantPlugins['prefersContrastVariants'],
variantPlugins['screenVariants'],
variantPlugins['orientationVariants'],
variantPlugins['directionVariants'],
variantPlugins['reducedMotionVariants'],
variantPlugins['darkVariants'],
variantPlugins['screenVariants'],
variantPlugins['forcedColorsVariants'],
variantPlugins['printVariant'],
]
// This is a compatibility fix for the pre 3.4 dark mode behavior
// `class` retains the old behavior, but `selector` keeps the new behavior
let isLegacyDarkMode =
context.tailwindConfig.darkMode === 'class' ||
(Array.isArray(context.tailwindConfig.darkMode) &&
context.tailwindConfig.darkMode[0] === 'class')
if (isLegacyDarkMode) {
afterVariants = [
variantPlugins['supportsVariants'],
variantPlugins['reducedMotionVariants'],
variantPlugins['prefersContrastVariants'],
variantPlugins['darkVariants'],
variantPlugins['screenVariants'],
variantPlugins['orientationVariants'],
variantPlugins['directionVariants'],
variantPlugins['forcedColorsVariants'],
variantPlugins['printVariant'],
]
}
return [...corePluginList, ...beforeVariants, ...userPlugins, ...afterVariants, ...layerPlugins]

@@ -563,9 +837,7 @@ }

let variantMap = new Map()
let offsets = {
base: 0n,
components: 0n,
utilities: 0n,
user: 0n,
}
context.variantMap = variantMap
let offsets = new Offsets()
context.offsets = offsets
let classList = new Set()

@@ -590,39 +862,13 @@

let highestOffset = ((args) => args.reduce((m, e) => (e > m ? e : m)))([
offsets.base,
offsets.components,
offsets.utilities,
offsets.user,
])
let reservedBits = BigInt(highestOffset.toString(2).length)
// Make sure to record bit masks for every variant
offsets.recordVariants(variantList, (variant) => variantMap.get(variant).length)
context.layerOrder = {
base: (1n << reservedBits) << 0n,
components: (1n << reservedBits) << 1n,
utilities: (1n << reservedBits) << 2n,
user: (1n << reservedBits) << 3n,
}
reservedBits += 4n
let offset = 0
context.variantOrder = new Map(
variantList
.map((variant, i) => {
let variantFunctions = variantMap.get(variant).length
let bits = (1n << BigInt(i + offset)) << reservedBits
offset += variantFunctions - 1
return [variant, bits]
})
.sort(([, a], [, z]) => bigSign(a - z))
)
context.minimumScreen = [...context.variantOrder.values()].shift()
// Build variantMap
for (let [variantName, variantFunctions] of variantMap.entries()) {
let sort = context.variantOrder.get(variantName)
context.variantMap.set(
variantName,
variantFunctions.map((variantFunction, idx) => [sort << BigInt(idx), variantFunction])
variantFunctions.map((variantFunction, idx) => [
offsets.forVariant(variantName, idx),
variantFunction,
])
)

@@ -645,3 +891,3 @@ }

'Update your `safelist` configuration to eliminate this warning.',
// TODO: Add https://tw.wtf/regex-safelist
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
])

@@ -656,2 +902,4 @@ continue

let patternMatchingCount = new Map()
let prefixLength = context.tailwindConfig.prefix.length
let checkImportantUtils = checks.some((check) => check.pattern.source.includes('!'))

@@ -662,3 +910,38 @@ for (let util of classList) {

let [utilName, options] = util
return Object.keys(options?.values ?? {}).map((value) => formatClass(utilName, value))
let values = Object.keys(options?.values ?? {})
let classes = values.map((value) => formatClass(utilName, value))
if (options?.supportsNegativeValues) {
// This is the normal negated version
// e.g. `-inset-1` or `-tw-inset-1`
classes = [...classes, ...classes.map((cls) => '-' + cls)]
// This is the negated version *after* the prefix
// e.g. `tw--inset-1`
// The prefix is already attached to util name
// So we add the negative after the prefix
classes = [
...classes,
...classes.map(
(cls) => cls.slice(0, prefixLength) + '-' + cls.slice(prefixLength)
),
]
}
if (options.types.some(({ type }) => type === 'color')) {
classes = [
...classes,
...classes.flatMap((cls) =>
Object.keys(context.tailwindConfig.theme.opacity).map(
(opacity) => `${cls}/${opacity}`
)
),
]
}
if (checkImportantUtils && options?.respectImportant) {
classes = [...classes, ...classes.map((cls) => '!' + cls)]
}
return classes
})()

@@ -698,2 +981,3 @@ : [util]

'Fix this pattern or remove it from your `safelist` configuration.',
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
])

@@ -704,5 +988,57 @@ }

let darkClassName = [].concat(context.tailwindConfig.darkMode ?? 'media')[1] ?? 'dark'
// A list of utilities that are used by certain Tailwind CSS utilities but
// that don't exist on their own. This will result in them "not existing" and
// sorting could be weird since you still require them in order to make the
// host utilities work properly. (Thanks Biology)
let parasiteUtilities = [
prefix(context, darkClassName),
prefix(context, 'group'),
prefix(context, 'peer'),
]
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(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(sorted), context, true)
rules = context.offsets.sort(rules)
let idx = BigInt(parasiteUtilities.length)
for (const [, rule] of rules) {
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++)
}
return classes.map((className) => {
let order = sortedClassNames.get(className) ?? null
let parasiteIndex = parasiteUtilities.indexOf(className)
if (order === null && parasiteIndex !== -1) {
// This will make sure that it is at the very beginning of the
// `components` layer which technically means 'before any
// components'.
order = BigInt(parasiteIndex)
}
return [className, order]
})
}
// Generate a list of strings for autocompletion purposes, e.g.
// ['uppercase', 'lowercase', ...]
context.getClassList = function () {
context.getClassList = function getClassList(options = {}) {
let output = []

@@ -712,10 +1048,27 @@

if (Array.isArray(util)) {
let [utilName, options] = util
let [utilName, utilOptions] = util
let negativeClasses = []
for (let [key, value] of Object.entries(options?.values ?? {})) {
output.push(formatClass(utilName, key))
if (options?.supportsNegativeValues && negateValue(value)) {
negativeClasses.push(formatClass(utilName, `-${key}`))
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
if (value == null) {
continue
}
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)
}
}

@@ -731,4 +1084,212 @@

}
// Generate a list of available variants with meta information of the type of variant.
context.getVariants = function getVariants() {
// We use a unique, random ID for candidate names to avoid conflicts
// We can't use characters like `_`, `:`, `@` or `.` because they might
// be used as a separator
let id = Math.random().toString(36).substring(7).toUpperCase()
let result = []
for (let [name, options] of context.variantOptions.entries()) {
if (options.variantInfo === VARIANT_INFO.Base) continue
result.push({
name,
isArbitrary: options.type === Symbol.for('MATCH_VARIANT'),
values: Object.keys(options.values ?? {}),
hasDash: name !== '@',
selectors({ modifier, value } = {}) {
let candidate = `TAILWINDPLACEHOLDER${id}`
let rule = postcss.rule({ selector: `.${candidate}` })
let container = postcss.root({ nodes: [rule.clone()] })
let before = container.toString()
let fns = (context.variantMap.get(name) ?? []).flatMap(([_, fn]) => fn)
let formatStrings = []
for (let fn of fns) {
let localFormatStrings = []
let api = {
args: { modifier, value: options.values?.[value] ?? value },
separator: context.tailwindConfig.separator,
modifySelectors(modifierFunction) {
// Run the modifierFunction over each rule
container.each((rule) => {
if (rule.type !== 'rule') {
return
}
rule.selectors = rule.selectors.map((selector) => {
return modifierFunction({
get className() {
return getClassNameFromSelector(selector)
},
selector,
})
})
})
return container
},
format(str) {
localFormatStrings.push(str)
},
wrap(wrapper) {
localFormatStrings.push(`@${wrapper.name} ${wrapper.params} { & }`)
},
container,
}
let ruleWithVariant = fn(api)
if (localFormatStrings.length > 0) {
formatStrings.push(localFormatStrings)
}
if (Array.isArray(ruleWithVariant)) {
for (let variantFunction of ruleWithVariant) {
localFormatStrings = []
variantFunction(api)
formatStrings.push(localFormatStrings)
}
}
}
// Reverse engineer the result of the `container`
let manualFormatStrings = []
let after = container.toString()
if (before !== after) {
// Figure out all selectors
container.walkRules((rule) => {
let modified = rule.selector
// Rebuild the base selector, this is what plugin authors would do
// as well. E.g.: `${variant}${separator}${className}`.
// However, plugin authors probably also prepend or append certain
// classes, pseudos, ids, ...
let rebuiltBase = selectorParser((selectors) => {
selectors.walkClasses((classNode) => {
classNode.value = `${name}${context.tailwindConfig.separator}${classNode.value}`
})
}).processSync(modified)
// Now that we know the original selector, the new selector, and
// the rebuild part in between, we can replace the part that plugin
// authors need to rebuild with `&`, and eventually store it in the
// collectedFormats. Similar to what `format('...')` would do.
//
// E.g.:
// variant: foo
// selector: .markdown > p
// modified (by plugin): .foo .foo\\:markdown > p
// rebuiltBase (internal): .foo\\:markdown > p
// format: .foo &
manualFormatStrings.push(modified.replace(rebuiltBase, '&').replace(candidate, '&'))
})
// Figure out all atrules
container.walkAtRules((atrule) => {
manualFormatStrings.push(`@${atrule.name} (${atrule.params}) { & }`)
})
}
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}`, '&')
.replace('{ & }', '')
.trim()
)
if (manualFormatStrings.length > 0) {
result.push(
formatVariantSelector(manualFormatStrings, opts)
.toString()
.replace(`.${candidate}`, '&')
)
}
return result
},
})
}
return result
}
}
/**
* Mark as class as retroactively invalid
*
*
* @param {string} candidate
*/
function markInvalidUtilityCandidate(context, candidate) {
if (!context.classCache.has(candidate)) {
return
}
// Mark this as not being a real utility
context.notClassCache.add(candidate)
// Remove it from any candidate-specific caches
context.classCache.delete(candidate)
context.applyClassCache.delete(candidate)
context.candidateRuleMap.delete(candidate)
context.candidateRuleCache.delete(candidate)
// Ensure the stylesheet gets rebuilt
context.stylesheetCache = null
}
/**
* Mark as class as retroactively invalid
*
* @param {import('postcss').Node} node
*/
function markInvalidUtilityNode(context, node) {
let candidate = node.raws.tailwind.candidate
if (!candidate) {
return
}
for (const entry of context.ruleCache) {
if (entry[1].raws.tailwind.candidate === candidate) {
context.ruleCache.delete(entry)
// context.postCssNodeCache.delete(node)
}
}
markInvalidUtilityCandidate(context, candidate)
}
export function createContext(tailwindConfig, changedContent = [], root = postcss.root()) {

@@ -738,5 +1299,7 @@ let context = {

ruleCache: new Set(),
candidateRuleCache: new Map(),
classCache: new Map(),
applyClassCache: new Map(),
notClassCache: new Set(),
// Seed the not class cache with the blocklist (which is only strings)
notClassCache: new Set(tailwindConfig.blocklist ?? []),
postCssNodeCache: new Map(),

@@ -748,2 +1311,6 @@ candidateRuleMap: new Map(),

stylesheetCache: null,
variantOptions: new Map(),
markInvalidUtilityCandidate: (candidate) => markInvalidUtilityCandidate(context, candidate),
markInvalidUtilityNode: (node) => markInvalidUtilityNode(context, node),
}

@@ -786,11 +1353,13 @@

let cssDidChange = 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],
getFileModifiedMap(existingContext)
)
if (!contextDependenciesChanged) {
return [existingContext, false]
if (!contextDependenciesChanged && !cssDidChange) {
return [existingContext, false, mtimesToCommit]
}

@@ -826,4 +1395,8 @@ }

trackModified([...contextDependencies], getFileModifiedMap(context))
Object.assign(context, {
userConfigPath,
})
let [, mtimesToCommit] = trackModified([...contextDependencies], getFileModifiedMap(context))
// ---

@@ -842,3 +1415,3 @@

return [context, true]
return [context, true, mtimesToCommit]
}

@@ -0,19 +1,15 @@

// @ts-check
import fs from 'fs'
import path from 'path'
import LRU from '@alloc/quick-lru'
import fastGlob from 'fast-glob'
import LRU from 'quick-lru'
import normalizePath from 'normalize-path'
import hash from '../util/hashConfig'
import getModuleDependencies from '../lib/getModuleDependencies'
import resolveConfig from '../public/resolve-config'
import resolveConfigPath from '../util/resolveConfigPath'
import { env } from './sharedState'
import { getContext, getFileModifiedMap } from './setupContextUtils'
import parseDependency from '../util/parseDependency'
import { validateConfig } from '../util/validateConfig.js'
import { parseCandidateFiles, resolvedChangedContent } from './content.js'
import { loadConfig } from '../lib/load-config'
import getModuleDependencies from './getModuleDependencies'

@@ -29,5 +25,3 @@ let configPathCache = new LRU({ maxSize: 100 })

let candidateFiles = tailwindConfig.content.files
.filter((item) => typeof item === 'string')
.map((contentPath) => normalizePath(contentPath))
let candidateFiles = parseCandidateFiles(context, tailwindConfig)

@@ -45,3 +39,3 @@ return candidateFilesCache.set(context, candidateFiles).get(context)

let newDeps = getModuleDependencies(userConfigPath).map((dep) => dep.file)
let newDeps = getModuleDependencies(userConfigPath)

@@ -67,3 +61,3 @@ let modified = false

}
let newConfig = resolveConfig(require(userConfigPath))
let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath)))
let newHash = hash(newConfig)

@@ -75,39 +69,9 @@ 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 ?? {})
newConfig = validateConfig(newConfig)
return [newConfig, null, hash(newConfig), []]
}
function resolvedChangedContent(context, candidateFiles, fileModifiedMap) {
let changedContent = context.tailwindConfig.content.files
.filter((item) => typeof item.raw === 'string')
.map(({ raw, extension = 'html' }) => ({ content: raw, extension }))
for (let changedFile of resolveChangedFiles(candidateFiles, fileModifiedMap)) {
let content = fs.readFileSync(changedFile, 'utf8')
let extension = path.extname(changedFile).slice(1)
changedContent.push({ content, extension })
}
return changedContent
}
function resolveChangedFiles(candidateFiles, fileModifiedMap) {
let changedFiles = new Set()
env.DEBUG && console.time('Finding changed files')
let files = fastGlob.sync(candidateFiles)
for (let file of files) {
let prevModified = fileModifiedMap.has(file) ? fileModifiedMap.get(file) : -Infinity
let modified = fs.statSync(file).mtimeMs
if (modified > prevModified) {
changedFiles.add(file)
fileModifiedMap.set(file, modified)
}
}
env.DEBUG && console.timeEnd('Finding changed files')
return changedFiles
}
// DISABLE_TOUCH = TRUE

@@ -126,7 +90,8 @@

// If there are no @tailwind rules, we don't consider this CSS file or it's dependencies
// to be dependencies of the context. Can reuse the context even if they change.
// We may want to think about `@layer` being part of this trigger too, but it's tough
// because it's impossible for a layer in one file to end up in the actual @tailwind rule
// in another file since independent sources are effectively isolated.
// If there are no @tailwind or @apply rules, we don't consider this CSS
// file or its dependencies to be dependencies of the context. Can reuse
// the context even if they change. We may want to think about `@layer`
// being part of this trigger too, but it's tough because it's impossible
// for a layer in one file to end up in the actual @tailwind rule in
// another file since independent sources are effectively isolated.
if (tailwindDirectives.size > 0) {

@@ -144,3 +109,3 @@ // Add current css file as a context dependencies.

let [context] = getContext(
let [context, , mTimesToCommit] = getContext(
root,

@@ -154,6 +119,8 @@ result,

let fileModifiedMap = getFileModifiedMap(context)
let candidateFiles = getCandidateFiles(context, tailwindConfig)
// If there are no @tailwind rules, we don't consider this CSS file or it's dependencies
// to be dependencies of the context. Can reuse the context even if they change.
// If there are no @tailwind or @apply rules, we don't consider this CSS file or it's
// dependencies to be dependencies of the context. Can reuse the context even if they change.
// We may want to think about `@layer` being part of this trigger too, but it's tough

@@ -163,8 +130,5 @@ // because it's impossible for a layer in one file to end up in the actual @tailwind rule

if (tailwindDirectives.size > 0) {
let fileModifiedMap = getFileModifiedMap(context)
// Add template paths as postcss dependencies.
for (let fileOrGlob of candidateFiles) {
let dependency = parseDependency(fileOrGlob)
if (dependency) {
for (let contentPath of candidateFiles) {
for (let dependency of parseDependency(contentPath)) {
registerDependency(dependency)

@@ -174,9 +138,25 @@ }

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)
}
}

@@ -188,2 +168,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

@@ -190,0 +177,0 @@ }

@@ -1,10 +0,57 @@

export const env = {
TAILWIND_MODE: process.env.TAILWIND_MODE,
NODE_ENV: process.env.NODE_ENV,
DEBUG: process.env.DEBUG !== undefined,
TAILWIND_DISABLE_TOUCH: process.env.TAILWIND_DISABLE_TOUCH !== undefined,
TAILWIND_TOUCH_DIR: process.env.TAILWIND_TOUCH_DIR,
}
export const env =
typeof process !== 'undefined'
? {
NODE_ENV: process.env.NODE_ENV,
DEBUG: resolveDebug(process.env.DEBUG),
}
: {
NODE_ENV: 'production',
DEBUG: false,
}
export const contextMap = new Map()
export const configContextMap = new Map()
export const contextSourcesMap = new Map()
export const sourceHashMap = new Map()
export const NOT_ON_DEMAND = new String('*')
export const NONE = Symbol('__NONE__')
export function resolveDebug(debug) {
if (debug === undefined) {
return false
}
// Environment variables are strings, so convert to boolean
if (debug === 'true' || debug === '1') {
return true
}
if (debug === 'false' || debug === '0') {
return false
}
// Keep the debug convention into account:
// DEBUG=* -> This enables all debug modes
// DEBUG=projectA,projectB,projectC -> This enables debug for projectA, projectB and projectC
// DEBUG=projectA:* -> This enables all debug modes for projectA (if you have sub-types)
// DEBUG=projectA,-projectB -> This enables debug for projectA and explicitly disables it for projectB
if (debug === '*') {
return true
}
let debuggers = debug.split(',').map((d) => d.split(':')[0])
// Ignoring tailwindcss
if (debuggers.includes('-tailwindcss')) {
return false
}
// Including tailwindcss
if (debuggers.includes('tailwindcss')) {
return true
}
return false
}

@@ -0,1 +1,2 @@

import { normalizeScreens } from '../util/normalizeScreens'
import buildMediaQuery from '../util/buildMediaQuery'

@@ -6,5 +7,7 @@

css.walkAtRules('screen', (atRule) => {
const screen = atRule.params
let screen = atRule.params
let screens = normalizeScreens(theme.screens)
let screenDefinition = screens.find(({ name }) => name === screen)
if (!theme.screens?.hasOwnProperty?.(screen)) {
if (!screenDefinition) {
throw atRule.error(`No \`${screen}\` screen found.`)

@@ -14,5 +17,5 @@ }

atRule.name = 'media'
atRule.params = buildMediaQuery(theme.screens[screen])
atRule.params = buildMediaQuery(screenDefinition)
})
}
}

@@ -8,3 +8,4 @@ import normalizeTailwindDirectives from './lib/normalizeTailwindDirectives'

import collapseAdjacentRules from './lib/collapseAdjacentRules'
import detectNesting from './lib/detectNesting'
import collapseDuplicateDeclarations from './lib/collapseDuplicateDeclarations'
import partitionApplyAtRules from './lib/partitionApplyAtRules'
import { createContext } from './lib/setupContextUtils'

@@ -14,7 +15,12 @@ import { issueFlagNotices } from './featureFlags'

export default function processTailwindFeatures(setupContext) {
return function (root, result) {
let tailwindDirectives = normalizeTailwindDirectives(root)
return async function (root, result) {
let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root)
// Partition apply rules that are found in the css
// itself.
partitionApplyAtRules()(root, result)
let context = setupContext({
tailwindDirectives,
applyDirectives,
registerDependency(dependency) {

@@ -40,4 +46,7 @@ result.messages.push({

detectNesting(context)(root, result)
expandTailwindAtRules(context)(root, result)
await expandTailwindAtRules(context)(root, result)
// Partition apply rules that are generated by
// addComponents, addUtilities and so on.
partitionApplyAtRules()(root, result)
expandApplyAtRules(context)(root, result)

@@ -48,3 +57,4 @@ evaluateTailwindFunctions(context)(root, result)

collapseAdjacentRules(context)(root, result)
collapseDuplicateDeclarations(context)(root, result)
}
}

@@ -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)
export default function buildMediaQuery(screens) {
if (typeof screens === 'string') {
screens = { min: screens }
}
screens = Array.isArray(screens) ? screens : [screens]
if (!Array.isArray(screens)) {
screens = [screens]
}
return screens
.map((screen) => {
if (screen?.hasOwnProperty?.('raw')) {
return screen.raw
}
let values = screen.values.map((screen) => {
if (screen.raw !== undefined) {
return screen.raw
}
return Object.entries(screen)
.map(([feature, value]) => {
feature = { min: 'min-width', max: 'max-width' }[feature] ?? feature
return `(${feature}: ${value})`
})
.join(' and ')
return [
screen.min && `(min-width: ${screen.min})`,
screen.max && `(max-width: ${screen.max})`,
]
.filter(Boolean)
.join(' and ')
})
return screen.not ? `not all and ${values}` : values
})
.join(', ')
}

@@ -1,7 +0,31 @@

export default function cloneNodes(nodes, source) {
/**
* @param {import('postcss').Container[]} nodes
* @param {any} source
* @param {any} raws
* @returns {import('postcss').Container[]}
*/
export default function cloneNodes(nodes, source = undefined, raws = undefined) {
return nodes.map((node) => {
let cloned = node.clone()
if (raws !== undefined) {
cloned.raws.tailwind = {
...cloned.raws.tailwind,
...raws,
}
}
if (source !== undefined) {
cloned.source = source
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
})
}

@@ -12,1 +36,15 @@

}
/**
* 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,13 +0,20 @@

import namedColors from 'color-name'
import namedColors from './colorNames'
let HEX = /^#([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i
let SHORT_HEX = /^#([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i
let VALUE = `(?:\\d+|\\d*\\.\\d+)%?`
let SEP = `(?:\\s*,\\s*|\\s+)`
let ALPHA_SEP = `\\s*[,/]\\s*`
let RGB_HSL = new RegExp(
`^(rgb|hsl)a?\\(\\s*(${VALUE})${SEP}(${VALUE})${SEP}(${VALUE})(?:${ALPHA_SEP}(${VALUE}))?\\s*\\)$`
let VALUE = /(?:\d+|\d*\.\d+)%?/
let SEP = /(?:\s*,\s*|\s+)/
let ALPHA_SEP = /\s*[,/]\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*\\)$`
)
export function parseColor(value) {
// In "loose" mode the color may contain fewer than 3 parts, as long as at least
// one of the parts is variable.
export function parseColor(value, { loose = false } = {}) {
if (typeof value !== 'string') {

@@ -40,13 +47,33 @@ return null

let match = value.match(RGB_HSL)
let match = value.match(RGB) ?? value.match(HSL)
if (match !== null) {
if (match === null) {
return null
}
let color = [match[2], match[3], match[4]].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: [match[2], match[3], match[4]].map((v) => v.toString()),
alpha: match[5]?.toString?.(),
color: [color[0]],
alpha: color[1],
}
}
return null
if (!loose && color.length !== 3) {
return null
}
if (color.length < 3 && !color.some((part) => /^var\(.*?\)$/.test(part))) {
return null
}
return {
mode: match[1],
color,
alpha: match[5]?.toString?.(),
}
}

@@ -56,3 +83,8 @@

let hasAlpha = alpha !== undefined
if (mode === 'rgba' || mode === 'hsla') {
return `${mode}(${color.join(', ')}${hasAlpha ? `, ${alpha}` : ''})`
}
return `${mode}(${color.join(' ')}${hasAlpha ? ` / ${alpha}` : ''})`
}
import { parseColor } from './color'
import { parseBoxShadowValue } from './parseBoxShadowValue'
import { splitAtTopLevelOnly } from './splitAtTopLevelOnly'
let cssFunctions = ['min', 'max', 'clamp', 'calc']
// Ref: https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Types
let COMMA = /,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
let UNDERSCORE = /_(?![^(]*\))/g // Underscore separator that is not located between brackets. E.g.: `rgba(255,_255,_255)_black` these don't count.
function isCSSFunction(value) {
return cssFunctions.some((fn) => new RegExp(`^${fn}\\(.*\\)`).test(value))
}
// 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
// - https://www.w3.org/TR/css-anchor-position-1
//
const AUTO_VAR_INJECTION_EXCEPTIONS = new Set([
// Concrete properties
'scroll-timeline-name',
'timeline-scope',
'view-timeline-name',
'font-palette',
'anchor-name',
'anchor-scope',
'position-anchor',
'position-try-options',
// Shorthand properties
'scroll-timeline',
'animation-timeline',
'view-timeline',
'position-try',
])
// This is not a data type, but rather a function that can normalize the
// correct values.
export function normalize(value) {
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(`
if (value.includes('url(')) {
return value
.split(/(url\(.*?\))/g)
.filter(Boolean)
.map((part) => {
if (/^url\(.*?\)$/.test(part)) {
return part
}
return normalize(part, context, false)
})
.join('')
}
// Convert `_` to ` `, except for escaped underscores `\_`

@@ -21,15 +75,155 @@ value = value

// Remove leftover whitespace
value = value.trim()
if (isRoot) {
value = value.trim()
}
// Keep raw strings if it starts with `url(`
if (value.startsWith('url(')) return value
value = normalizeMathOperatorSpacing(value)
// Add spaces around operators inside calc() that do not follow an operator
// or '('.
return value.replace(
/(-?\d*\.?\d(?!\b-.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g,
'$1 $2 '
)
return value
}
export function normalizeAttributeSelectors(value) {
// Wrap values in attribute selectors with quotes
if (value.includes('=')) {
value = value.replace(/(=.*)/g, (_fullMatch, match) => {
if (match[1] === "'" || match[1] === '"') {
return match
}
// Handle regex flags on unescaped values
if (match.length > 2) {
let trailingCharacter = match[match.length - 1]
if (
match[match.length - 2] === ' ' &&
(trailingCharacter === 'i' ||
trailingCharacter === 'I' ||
trailingCharacter === 's' ||
trailingCharacter === 'S')
) {
return `="${match.slice(1, -2)}" ${match[match.length - 1]}`
}
}
return `="${match.slice(1)}"`
})
}
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',
'radial-gradient',
'linear-gradient',
'conic-gradient',
'repeating-radial-gradient',
'repeating-linear-gradient',
'repeating-conic-gradient',
'anchor-size',
]
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([')'])
}
// Don't break CSS grid track names
else if (peek('[')) {
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) {

@@ -40,9 +234,12 @@ return value.startsWith('url(')

export function number(value) {
return !isNaN(Number(value))
return !isNaN(Number(value)) || isCSSFunction(value)
}
export function percentage(value) {
return /%$/g.test(value) || /^calc\(.+?%\)/g.test(value)
return (value.endsWith('%') && number(value.slice(0, -1))) || isCSSFunction(value)
}
// 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 = [

@@ -61,2 +258,3 @@ 'cm',

'lh',
'rlh',
'vw',

@@ -66,2 +264,16 @@ 'vh',

'vmax',
'vb',
'vi',
'svw',
'svh',
'lvw',
'lvh',
'dvw',
'dvh',
'cqw',
'cqh',
'cqi',
'cqb',
'cqmin',
'cqmax',
]

@@ -71,4 +283,5 @@ let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`

return (
new RegExp(`${lengthUnitsPattern}$`).test(value) ||
new RegExp(`^calc\\(.+?${lengthUnitsPattern}`).test(value)
value === '0' ||
new RegExp(`^[+-]?[0-9]*\.?[0-9]+(?:[eE][+-]?[0-9]+)?${lengthUnitsPattern}$`).test(value) ||
isCSSFunction(value)
)

@@ -82,10 +295,22 @@ }

export function shadow(value) {
let parsedShadows = parseBoxShadowValue(normalize(value))
for (let parsedShadow of parsedShadows) {
if (!parsedShadow.valid) {
return false
}
}
return true
}
export function color(value) {
let colors = 0
let result = value.split(UNDERSCORE).every((part) => {
let result = splitAtTopLevelOnly(value, '_').every((part) => {
part = normalize(part)
if (part.startsWith('var(')) return true
if (parseColor(part) !== null) return colors++, true
if (parseColor(part, { loose: true }) !== null) return colors++, true

@@ -101,3 +326,3 @@ return false

let images = 0
let result = value.split(COMMA).every((part) => {
let result = splitAtTopLevelOnly(value, ',').every((part) => {
part = normalize(part)

@@ -123,7 +348,8 @@

let gradientTypes = new Set([
'conic-gradient',
'linear-gradient',
'radial-gradient',
'repeating-conic-gradient',
'repeating-linear-gradient',
'repeating-radial-gradient',
'conic-gradient',
])

@@ -144,3 +370,3 @@ export function gradient(value) {

let positions = 0
let result = value.split(UNDERSCORE).every((part) => {
let result = splitAtTopLevelOnly(value, '_').every((part) => {
part = normalize(part)

@@ -163,3 +389,3 @@

let fonts = 0
let result = value.split(COMMA).every((part) => {
let result = splitAtTopLevelOnly(value, ',').every((part) => {
part = normalize(part)

@@ -216,3 +442,3 @@

'x-large',
'x-large',
'xx-large',
'xxx-large',

@@ -219,0 +445,0 @@ ])

@@ -8,2 +8,8 @@ export function defaults(target, ...sources) {

}
for (let k of Object.getOwnPropertySymbols(source)) {
if (!target?.hasOwnProperty?.(k)) {
target[k] = source[k]
}
}
}

@@ -10,0 +16,0 @@

@@ -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()

@@ -12,2 +12,21 @@ .reverse()

// Add experimental configs here...
respectDefaultRingColorOpacity: {
theme: {
ringColor: ({ theme }) => ({
DEFAULT: '#3b82f67f',
...theme('colors'),
}),
},
},
disableColorOpacityUtilitiesByDefault: {
corePlugins: {
backgroundOpacity: false,
borderOpacity: false,
divideOpacity: false,
placeholderOpacity: false,
ringOpacity: false,
textOpacity: false,
},
},
}

@@ -14,0 +33,0 @@

@@ -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,7 +0,7 @@

import chalk from 'chalk'
import colors from 'picocolors'
let alreadyShown = new Set()
function log(chalk, messages, key) {
if (process.env.JEST_WORKER_ID !== undefined) return
function log(type, messages, key) {
if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return

@@ -12,15 +12,19 @@ if (key && alreadyShown.has(key)) return

console.warn('')
messages.forEach((message) => console.warn(chalk, '-', message))
messages.forEach((message) => console.warn(type, '-', message))
}
export function dim(input) {
return colors.dim(input)
}
export default {
info(key, messages) {
log(chalk.bold.cyan('info'), ...(Array.isArray(key) ? [key] : [messages, key]))
log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key]))
},
warn(key, messages) {
log(chalk.bold.yellow('warn'), ...(Array.isArray(key) ? [key] : [messages, key]))
log(colors.bold(colors.yellow('warn')), ...(Array.isArray(key) ? [key] : [messages, key]))
},
risk(key, messages) {
log(chalk.bold.magenta('risk'), ...(Array.isArray(key) ? [key] : [messages, key]))
log(colors.bold(colors.magenta('risk')), ...(Array.isArray(key) ? [key] : [messages, key]))
},
}
import escapeClassName from './escapeClassName'
import escapeCommas from './escapeCommas'
function asClass(name) {
export function asClass(name) {
return escapeCommas(`.${escapeClassName(name)}`)

@@ -25,3 +25,7 @@ }

if (key.startsWith('/')) {
return `${classPrefix}${key}`
}
return `${classPrefix}-${key}`
}

@@ -1,2 +0,2 @@

export default function (value) {
export default function negateValue(value) {
value = `${value}`

@@ -13,5 +13,13 @@

if (value.includes('var(') || value.includes('calc(')) {
return `calc(${value} * -1)`
// What functions we support negating numeric values for
// var() isn't inherently a numeric function but we support it anyway
// The trigonometric functions are omitted because you'll need to use calc(…) with them _anyway_
// to produce generally useful results and that will be covered already
let numericFunctions = ['var', 'calc', 'min', 'max', 'clamp']
for (const fn of numericFunctions) {
if (value.includes(`${fn}(`)) {
return `calc(${value} * -1)`
}
}
}

@@ -1,2 +0,3 @@

import log from './log'
import { flagEnabled } from '../featureFlags'
import log, { dim } from './log'

@@ -59,5 +60,7 @@ export function normalizeConfig(config) {

if (typeof config.content === 'object' && config.content !== null) {
// Only `files`, `extract` and `transform` can exist in `config.content`
// Only `files`, `relative`, `extract`, and `transform` can exist in `config.content`
if (
Object.keys(config.content).some((key) => !['files', 'extract', 'transform'].includes(key))
Object.keys(config.content).some(
(key) => !['files', 'relative', 'extract', 'transform'].includes(key)
)
) {

@@ -116,2 +119,10 @@ return false

}
// `config.content.relative` is optional and can be a boolean
if (
typeof config.content.relative !== 'boolean' &&
typeof config.content.relative !== 'undefined'
) {
return false
}
}

@@ -129,3 +140,3 @@

'Update your configuration file to eliminate this warning.',
// TODO: Add https://tw.wtf/purge-deprecation
'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources',
])

@@ -146,4 +157,44 @@ }

// Normalize the `blocklist`
config.blocklist = (() => {
let { blocklist } = config
if (Array.isArray(blocklist)) {
if (blocklist.every((item) => typeof item === 'string')) {
return blocklist
}
log.warn('blocklist-invalid', [
'The `blocklist` option must be an array of strings.',
'https://tailwindcss.com/docs/content-configuration#discarding-classes',
])
}
return []
})()
// Normalize prefix option
if (typeof config.prefix === 'function') {
log.warn('prefix-function', [
'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
'Update `prefix` in your configuration to be a string to eliminate this warning.',
'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function',
])
config.prefix = ''
} else {
config.prefix = config.prefix ?? ''
}
// Normalize the `content`
config.content = {
relative: (() => {
let { content } = config
if (content?.relative) {
return content.relative
}
return flagEnabled(config, 'relativeContentPathsByDefault')
})(),
files: (() => {

@@ -177,3 +228,3 @@ let { content, purge } = config

extractors.DEFAULT = (() => {
let defaultExtractor = (() => {
if (config.purge?.options?.defaultExtractor) {

@@ -190,2 +241,6 @@ return config.purge.options.defaultExtractor

if (defaultExtractor !== undefined) {
extractors.DEFAULT = defaultExtractor
}
// Functions

@@ -228,5 +283,3 @@ if (typeof extract === 'function') {

transformers.DEFAULT = transform
}
if (typeof transform === 'object' && transform !== null) {
} else if (typeof transform === 'object' && transform !== null) {
Object.assign(transformers, transform)

@@ -239,3 +292,16 @@ }

// Validate globs to prevent bogus globs.
// E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html`
for (let file of config.content.files) {
if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
log.warn('invalid-glob-braces', [
`The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`,
`Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
// TODO: Add https://tw.wtf/invalid-glob-braces
])
break
}
}
return config
}

@@ -16,3 +16,3 @@ const DIRECTIONS = new Set(['normal', 'reverse', 'alternate', 'alternate-reverse'])

const COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
const COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubic-bezier(a, b, c)` these don't count.
const SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.

@@ -19,0 +19,0 @@ const TIME = /^(-?[\d.]+m?s)$/

@@ -1,49 +0,44 @@

import isGlob from 'is-glob'
import globParent from 'glob-parent'
import path from 'path'
// @ts-check
// Based on `glob-base`
// https://github.com/micromatch/glob-base/blob/master/index.js
function parseGlob(pattern) {
let glob = pattern
let base = globParent(pattern)
/**
* @typedef {{type: 'dependency', file: string} | {type: 'dir-dependency', dir: string, glob: string}} Dependency
*/
if (base !== '.') {
glob = pattern.substr(base.length)
if (glob.charAt(0) === '/') {
glob = glob.substr(1)
}
/**
*
* @param {import('../lib/content.js').ContentPath} contentPath
* @returns {Dependency[]}
*/
export default function parseDependency(contentPath) {
if (contentPath.ignore) {
return []
}
if (glob.substr(0, 2) === './') {
glob = glob.substr(2)
if (!contentPath.glob) {
return [
{
type: 'dependency',
file: contentPath.base,
},
]
}
if (glob.charAt(0) === '/') {
glob = glob.substr(1)
}
return { base, glob }
}
export default function parseDependency(normalizedFileOrGlob) {
if (normalizedFileOrGlob.startsWith('!')) {
return null
if (process.env.ROLLUP_WATCH === 'true') {
// rollup-plugin-postcss does not support dir-dependency messages
// but directories can be watched in the same way as files
return [
{
type: 'dependency',
file: contentPath.base,
},
]
}
let message
if (isGlob(normalizedFileOrGlob)) {
let { base, glob } = parseGlob(normalizedFileOrGlob)
message = { type: 'dir-dependency', dir: path.resolve(base), glob }
} else {
message = { type: 'dependency', file: path.resolve(normalizedFileOrGlob) }
}
// rollup-plugin-postcss does not support dir-dependency messages
// but directories can be watched in the same way as files
if (message.type === 'dir-dependency' && process.env.ROLLUP_WATCH === 'true') {
message = { type: 'dependency', file: message.dir }
}
return message
return [
{
type: 'dir-dependency',
dir: contentPath.base,
glob: contentPath.glob,
},
]
}

@@ -1,5 +0,3 @@

import selectorParser from 'postcss-selector-parser'
import escapeCommas from './escapeCommas'
import { withAlphaValue } from './withAlphaVariable'
import isKeyframeRule from './isKeyframeRule'
import {

@@ -19,154 +17,23 @@ normalize,

lineWidth,
shadow,
} from './dataTypes'
import negateValue from './negateValue'
import { backgroundSize } from './validateFormalSyntax'
import { flagEnabled } from '../featureFlags.js'
export function applyStateToMarker(selector, marker, state, join) {
let markerIdx = selector.search(new RegExp(`${marker}[:[]`))
if (markerIdx === -1) {
return join(marker + state, selector)
}
let markerSelector = selector.slice(markerIdx, selector.indexOf(' ', markerIdx))
return join(
marker + state + markerSelector.slice(markerIdx + marker.length),
selector.replace(markerSelector, '')
)
}
/**
* @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, {
withAttr(className, attr) {
sel.parent.insertAfter(sel, selectorParser.attribute({ attribute: attr.slice(1, -1) }))
return className
},
withPseudo(className, pseudo) {
sel.parent.insertAfter(sel, selectorParser.pseudo({ value: pseudo }))
return className
},
})
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 updateLastClasses(selectors, updateClass) {
let parser = selectorParser((selectors) => {
selectors.each((sel) => {
let lastClass = sel.filter(({ type }) => type === 'class').pop()
if (lastClass === undefined) {
return
}
let updatedClass = updateClass(lastClass.value, {
withPseudo(className, pseudo) {
lastClass.parent.insertAfter(lastClass, selectorParser.pseudo({ value: `${pseudo}` }))
return className
},
})
lastClass.value = updatedClass
if (lastClass.raws && lastClass.raws.value) {
lastClass.raws.value = escapeCommas(lastClass.raws.value)
}
})
if (sel.raws && sel.raws.value) {
sel.raws.value = escapeCommas(sel.raws.value)
}
})
let result = parser.processSync(selectors)
return result
}
function splitByNotEscapedCommas(str) {
let chunks = []
let currentChunk = ''
for (let i = 0; i < str.length; i++) {
if (str[i] === ',' && str[i - 1] !== '\\') {
chunks.push(currentChunk)
currentChunk = ''
} else {
currentChunk += str[i]
}
}
chunks.push(currentChunk)
return chunks
}
export function transformAllSelectors(transformSelector, { wrap, withRule } = {}) {
return ({ container }) => {
container.walkRules((rule) => {
if (isKeyframeRule(rule)) {
return rule
}
let transformed = splitByNotEscapedCommas(rule.selector).map(transformSelector).join(',')
rule.selector = transformed
if (withRule) {
withRule(rule)
}
return rule
})
if (wrap) {
let wrapper = wrap()
let nodes = container.nodes
container.removeAll()
wrapper.append(nodes)
container.append(wrapper)
}
}
}
export function transformAllClasses(transformClass, { wrap, withRule } = {}) {
return ({ container }) => {
container.walkRules((rule) => {
let selector = rule.selector
let variantSelector = updateAllClasses(selector, transformClass)
rule.selector = variantSelector
if (withRule) {
withRule(rule)
}
return rule
})
if (wrap) {
let wrapper = wrap()
let nodes = container.nodes
container.removeAll()
wrapper.append(nodes)
container.append(wrapper)
}
}
}
export function transformLastClasses(transformClass, { wrap, withRule } = {}) {
return ({ container }) => {
container.walkRules((rule) => {
let selector = rule.selector
let variantSelector = updateLastClasses(selector, transformClass)
rule.selector = variantSelector
if (withRule) {
withRule(rule)
}
return rule
})
if (wrap) {
let wrapper = wrap()
let nodes = container.nodes
container.removeAll()
wrapper.append(nodes)
container.append(wrapper)
}
}
}
function resolveArbitraryValue(modifier, validate) {

@@ -222,18 +89,59 @@ if (!isArbitraryValue(modifier)) {

function splitAlpha(modifier) {
function splitUtilityModifier(modifier) {
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) {
return [modifier]
return [modifier, undefined]
}
let arbitrary = isArbitraryValue(modifier)
// The modifier could be of the form `[foo]/[bar]`
// We want to handle this case properly
// without affecting `[foo/bar]`
if (arbitrary && !modifier.includes(']/[')) {
return [modifier, undefined]
}
return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
}
export function parseColorFormat(value) {
if (typeof value === 'string' && value.includes('<alpha-value>')) {
let oldValue = value
return ({ opacityValue = 1 }) => oldValue.replace(/<alpha-value>/g, opacityValue)
}
return value
}
function unwrapArbitraryModifier(modifier) {
return normalize(modifier.slice(1, -1))
}
export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
if (options.values?.[modifier] !== undefined) {
return options.values?.[modifier]
return parseColorFormat(options.values?.[modifier])
}
let [color, alpha] = splitAlpha(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(modifier)

@@ -248,4 +156,6 @@ if (alpha !== undefined) {

normalizedColor = parseColorFormat(normalizedColor)
if (isArbitraryValue(alpha)) {
return withAlphaValue(normalizedColor, alpha.slice(1, -1))
return withAlphaValue(normalizedColor, unwrapArbitraryModifier(alpha))
}

@@ -273,3 +183,3 @@

let typeMap = {
export let typeMap = {
any: asValue,

@@ -289,2 +199,4 @@ color: asColor,

'relative-size': guess(relativeSize),
shadow: guess(shadow),
size: guess(backgroundSize),
}

@@ -301,6 +213,29 @@

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)) {
let [explicitType, value] = splitAtFirst(modifier.slice(1, -1), ':')
let arbitraryValue = modifier.slice(1, -1)
let [explicitType, value] = splitAtFirst(arbitraryValue, ':')
if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
// It could be that this resolves to `url(https` which is not a valid
// identifier. We currently only support "simple" words with dashes or
// underscores. E.g.: family-name
if (!/^[\w-_]+$/g.test(explicitType)) {
value = arbitraryValue
}
//
else if (explicitType !== undefined && !supportedTypes.includes(explicitType)) {
return []

@@ -310,10 +245,11 @@ }

if (value.length > 0 && supportedTypes.includes(explicitType)) {
return [asValue(`[${value}]`, options), explicitType]
return [asValue(`[${value}]`, options), explicitType, null]
}
}
let matches = getMatchingTypes(types, modifier, options, tailwindConfig)
// Find first matching type
for (let type of [].concat(types)) {
let result = typeMap[type](modifier, options, { tailwindConfig })
if (result) return [result, type]
for (let match of matches) {
return match
}

@@ -323,1 +259,57 @@

}
/**
*
* @param {{type: string}[]} types
* @param {string} rawModifier
* @param {any} options
* @param {any} tailwindConfig
* @returns {Iterator<[value: string, type: string, modifier: string | null]>}
*/
export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
let [modifier, utilityModifier] = splitUtilityModifier(rawModifier)
let canUseUtilityModifier =
modifiersEnabled &&
options.modifiers != null &&
(options.modifiers === 'any' ||
(typeof options.modifiers === 'object' &&
((utilityModifier && isArbitraryValue(utilityModifier)) ||
utilityModifier in options.modifiers)))
if (!canUseUtilityModifier) {
modifier = rawModifier
utilityModifier = undefined
}
if (utilityModifier !== undefined && modifier === '') {
modifier = 'DEFAULT'
}
// Check the full value first
// TODO: Move to asValue… somehow
if (utilityModifier !== undefined) {
if (typeof options.modifiers === 'object') {
let configValue = options.modifiers?.[utilityModifier] ?? null
if (configValue !== null) {
utilityModifier = configValue
} else if (isArbitraryValue(utilityModifier)) {
utilityModifier = unwrapArbitraryModifier(utilityModifier)
}
}
}
for (let { type } of types ?? []) {
let result = typeMap[type](modifier, options, {
tailwindConfig,
})
if (result === undefined) {
continue
}
yield [result, type, utilityModifier ?? null]
}
}
import parser from 'postcss-selector-parser'
import { tap } from './tap'
export default function (prefix, selector) {
const getPrefix =
typeof prefix === 'function' ? prefix : () => (prefix === undefined ? '' : prefix)
/**
* @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) {
if (prefix === '') {
return selector
}
return parser((selectors) => {
selectors.walkClasses((classSelector) => {
tap(classSelector.value, (baseClass) => {
classSelector.value = `${getPrefix('.' + baseClass)}${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'

@@ -9,2 +8,7 @@ import { defaults } from './defaults'

import { normalizeConfig } from './normalizeConfig'
import isPlainObject from './isPlainObject'
import { cloneDeep } from './cloneDeep'
import { parseColorFormat } from './pluginUtils'
import { withAlphaValue } from './withAlphaVariable'
import toColorValue from './toColorValue'

@@ -15,6 +19,2 @@ function isFunction(input) {

function isObject(input) {
return typeof input === 'object' && input !== null
}
function mergeWith(target, ...sources) {

@@ -28,4 +28,4 @@ let customizer = sources.pop()

if (merged === undefined) {
if (isObject(target[k]) && isObject(source[k])) {
target[k] = mergeWith(target[k], source[k], customizer)
if (isPlainObject(target[k]) && isPlainObject(source[k])) {
target[k] = mergeWith({}, target[k], source[k], customizer)
} else {

@@ -104,3 +104,3 @@ target[k] = source[k]

// When we have an array of objects, we do want to merge it
if (Array.isArray(merged) && isObject(merged[0])) {
if (Array.isArray(merged) && isPlainObject(merged[0])) {
return merged.concat(value)

@@ -110,3 +110,3 @@ }

// When the incoming value is an array, and the existing config is an object, prepend the existing object
if (Array.isArray(value) && isObject(value[0]) && isObject(merged)) {
if (Array.isArray(value) && isPlainObject(value[0]) && isPlainObject(merged)) {
return [merged, ...value]

@@ -140,28 +140,77 @@ }

/**
*
* @param {string} key
* @return {Iterable<string[] & {alpha: string | undefined}>}
*/
function* toPaths(key) {
let path = toPath(key)
if (path.length === 0) {
return
}
yield path
if (Array.isArray(key)) {
return
}
let pattern = /^(.*?)\s*\/\s*([^/]+)$/
let matches = key.match(pattern)
if (matches !== null) {
let [, prefix, alpha] = matches
let newPath = toPath(prefix)
newPath.alpha = alpha
yield newPath
}
}
function resolveFunctionKeys(object) {
// theme('colors.red.500 / 0.5') -> ['colors', 'red', '500 / 0', '5]
const resolvePath = (key, defaultValue) => {
const path = toPath(key)
for (const path of toPaths(key)) {
let index = 0
let val = object
let index = 0
let val = object
while (val !== undefined && val !== null && index < path.length) {
val = val[path[index++]]
while (val !== undefined && val !== null && index < path.length) {
val = val[path[index++]]
val = isFunction(val) ? val(resolvePath, configUtils) : val
let shouldResolveAsFn =
isFunction(val) && (path.alpha === undefined || index <= path.length - 1)
val = shouldResolveAsFn ? val(resolvePath, configUtils) : val
}
if (val !== undefined) {
if (path.alpha !== undefined) {
let normalized = parseColorFormat(val)
return withAlphaValue(normalized, path.alpha, toColorValue(normalized))
}
if (isPlainObject(val)) {
return cloneDeep(val)
}
return val
}
}
return val === undefined ? defaultValue : val
return defaultValue
}
resolvePath.theme = resolvePath
Object.assign(resolvePath, {
theme: resolvePath,
...configUtils,
})
for (let key in configUtils) {
resolvePath[key] = configUtils[key]
}
return Object.keys(object).reduce((resolved, key) => {
resolved[key] = isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key]
return Object.keys(object).reduce((resolved, key) => {
return {
...resolved,
[key]: isFunction(object[key]) ? object[key](resolvePath, configUtils) : object[key],
}
return resolved
}, {})

@@ -219,3 +268,2 @@ }

separator: ':',
variantOrder: defaultConfig.variantOrder,
},

@@ -222,0 +270,0 @@ ]

import fs from 'fs'
import path from 'path'
const defaultConfigFiles = [
'./tailwind.config.js',
'./tailwind.config.cjs',
'./tailwind.config.mjs',
'./tailwind.config.ts',
'./tailwind.config.cts',
'./tailwind.config.mts',
]
function isObject(value) {

@@ -46,3 +55,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 +62,0 @@ const configPath = path.resolve(configFile)

@@ -0,4 +1,26 @@

/**
* Parse a path string into an array of path segments.
*
* Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
*
* Example:
* a -> ['a']
* a.b.c -> ['a', 'b', 'c']
* a[b].c -> ['a', 'b', 'c']
* a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
* a[b][c][d] -> ['a', 'b', 'c', 'd']
*
* @param {string|string[]} path
**/
export function toPath(path) {
if (Array.isArray(path)) return path
return path.split(/[\.\]\[]+/g)
let openBrackets = path.split('[').length - 1
let closedBrackets = path.split(']').length - 1
if (openBrackets !== closedBrackets) {
throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`)
}
return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean)
}
import postcss from 'postcss'
import isPlainObject from './isPlainObject'
export default function transformThemeValue(themeSection) {
if (['fontSize', 'outline'].includes(themeSection)) {
return (value) => (Array.isArray(value) ? value[0] : value)
return (value) => {
if (typeof value === 'function') value = value({})
if (Array.isArray(value)) value = value[0]
return value
}
}
if (themeSection === 'fontFamily') {
return (value) => {
if (typeof value === 'function') value = value({})
let families = Array.isArray(value) && isPlainObject(value[1]) ? value[0] : value
return Array.isArray(families) ? families.join(', ') : families
}
}
if (
[
'fontFamily',
'boxShadow',

@@ -23,3 +36,8 @@ 'transitionProperty',

) {
return (value) => (Array.isArray(value) ? value.join(', ') : value)
return (value) => {
if (typeof value === 'function') value = value({})
if (Array.isArray(value)) value = value.join(', ')
return value
}
}

@@ -30,10 +48,17 @@

if (['gridTemplateColumns', 'gridTemplateRows', 'objectPosition'].includes(themeSection)) {
return (value) => (typeof value === 'string' ? postcss.list.comma(value).join(' ') : value)
return (value) => {
if (typeof value === 'function') value = value({})
if (typeof value === 'string') value = postcss.list.comma(value).join(' ')
return value
}
}
if (themeSection === 'colors') {
return (value) => (typeof value === 'function' ? value({}) : value)
return (value, opts = {}) => {
if (typeof value === 'function') {
value = value(opts)
}
return value
}
return (value) => value
}

@@ -8,3 +8,3 @@ import { parseColor, formatColor } from './color'

let parsed = parseColor(color)
let parsed = parseColor(color, { loose: true })

@@ -11,0 +11,0 @@ if (parsed === null) {

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 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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc