tailwindcss 3.1.8 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +64 -3
- package/README.md +6 -5
- package/lib/cli/build/deps.js +54 -0
- package/lib/cli/build/index.js +44 -0
- package/lib/cli/build/plugin.js +351 -0
- package/lib/cli/build/utils.js +78 -0
- package/lib/cli/build/watching.js +113 -0
- package/lib/cli/help/index.js +71 -0
- package/lib/cli/index.js +18 -0
- package/lib/cli/init/index.js +46 -0
- package/lib/cli/shared.js +12 -0
- package/lib/cli.js +11 -590
- package/lib/corePlugins.js +332 -108
- package/lib/css/preflight.css +5 -0
- package/lib/featureFlags.js +7 -4
- package/lib/index.js +6 -1
- package/lib/lib/content.js +167 -0
- package/lib/lib/defaultExtractor.js +15 -10
- package/lib/lib/detectNesting.js +2 -2
- package/lib/lib/evaluateTailwindFunctions.js +17 -1
- package/lib/lib/expandApplyAtRules.js +66 -37
- package/lib/lib/expandTailwindAtRules.js +10 -42
- package/lib/lib/findAtConfigPath.js +44 -0
- package/lib/lib/generateRules.js +180 -93
- package/lib/lib/normalizeTailwindDirectives.js +1 -1
- package/lib/lib/offsets.js +217 -0
- package/lib/lib/regex.js +1 -1
- package/lib/lib/setupContextUtils.js +339 -100
- package/lib/lib/setupTrackingContext.js +5 -39
- package/lib/lib/sharedState.js +2 -0
- package/lib/public/colors.js +1 -1
- package/lib/util/buildMediaQuery.js +6 -3
- package/lib/util/configurePlugins.js +1 -1
- package/lib/util/dataTypes.js +15 -19
- package/lib/util/formatVariantSelector.js +92 -8
- package/lib/util/getAllConfigs.js +14 -3
- package/lib/util/isValidArbitraryValue.js +1 -1
- package/lib/util/nameClass.js +3 -0
- package/lib/util/negateValue.js +15 -2
- package/lib/util/normalizeConfig.js +17 -3
- package/lib/util/normalizeScreens.js +100 -3
- package/lib/util/parseAnimationValue.js +1 -1
- package/lib/util/parseBoxShadowValue.js +1 -1
- package/lib/util/parseDependency.js +33 -54
- package/lib/util/parseGlob.js +34 -0
- package/lib/util/parseObjectStyles.js +1 -1
- package/lib/util/pluginUtils.js +87 -17
- package/lib/util/resolveConfig.js +2 -2
- package/lib/util/splitAtTopLevelOnly.js +31 -81
- package/lib/util/transformThemeValue.js +9 -2
- package/lib/util/validateConfig.js +1 -1
- package/lib/util/validateFormalSyntax.js +24 -0
- package/package.json +14 -13
- package/peers/index.js +3263 -1887
- package/plugin.d.ts +3 -3
- package/scripts/release-channel.js +18 -0
- package/scripts/release-notes.js +21 -0
- package/src/cli/build/deps.js +56 -0
- package/src/cli/build/index.js +45 -0
- package/src/cli/build/plugin.js +417 -0
- package/src/cli/build/utils.js +76 -0
- package/src/cli/build/watching.js +134 -0
- package/src/cli/help/index.js +70 -0
- package/src/cli/index.js +3 -0
- package/src/cli/init/index.js +50 -0
- package/src/cli/shared.js +5 -0
- package/src/cli.js +4 -696
- package/src/corePlugins.js +262 -39
- package/src/css/preflight.css +5 -0
- package/src/featureFlags.js +12 -2
- package/src/index.js +5 -0
- package/src/lib/content.js +205 -0
- package/src/lib/defaultExtractor.js +3 -0
- package/src/lib/evaluateTailwindFunctions.js +22 -1
- package/src/lib/expandApplyAtRules.js +70 -29
- package/src/lib/expandTailwindAtRules.js +8 -46
- package/src/lib/findAtConfigPath.js +48 -0
- package/src/lib/generateRules.js +223 -101
- package/src/lib/offsets.js +270 -0
- package/src/lib/setupContextUtils.js +376 -89
- package/src/lib/setupTrackingContext.js +4 -45
- package/src/lib/sharedState.js +2 -0
- package/src/util/buildMediaQuery.js +5 -3
- package/src/util/dataTypes.js +15 -17
- package/src/util/formatVariantSelector.js +113 -9
- package/src/util/getAllConfigs.js +14 -2
- package/src/util/nameClass.js +4 -0
- package/src/util/negateValue.js +10 -2
- package/src/util/normalizeConfig.js +22 -2
- package/src/util/normalizeScreens.js +99 -4
- package/src/util/parseBoxShadowValue.js +1 -1
- package/src/util/parseDependency.js +37 -42
- package/src/util/parseGlob.js +24 -0
- package/src/util/pluginUtils.js +96 -14
- package/src/util/resolveConfig.js +1 -1
- package/src/util/splitAtTopLevelOnly.js +23 -49
- package/src/util/transformThemeValue.js +9 -1
- package/src/util/validateFormalSyntax.js +34 -0
- package/stubs/defaultConfig.stub.js +20 -3
- package/types/config.d.ts +48 -13
- package/types/generated/default-theme.d.ts +11 -0
package/lib/css/preflight.css
CHANGED
package/lib/featureFlags.js
CHANGED
|
@@ -21,16 +21,19 @@ function _interopRequireDefault(obj) {
|
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
23
|
let defaults = {
|
|
24
|
-
optimizeUniversalDefaults: false
|
|
24
|
+
optimizeUniversalDefaults: false,
|
|
25
|
+
generalizedModifiers: true
|
|
25
26
|
};
|
|
26
27
|
let featureFlags = {
|
|
27
28
|
future: [
|
|
28
29
|
"hoverOnlyWhenSupported",
|
|
29
|
-
"respectDefaultRingColorOpacity"
|
|
30
|
+
"respectDefaultRingColorOpacity",
|
|
31
|
+
"disableColorOpacityUtilitiesByDefault",
|
|
32
|
+
"relativeContentPathsByDefault"
|
|
30
33
|
],
|
|
31
34
|
experimental: [
|
|
32
35
|
"optimizeUniversalDefaults",
|
|
33
|
-
"
|
|
36
|
+
"generalizedModifiers"
|
|
34
37
|
]
|
|
35
38
|
};
|
|
36
39
|
function flagEnabled(config, flag) {
|
|
@@ -61,7 +64,7 @@ function issueFlagNotices(config) {
|
|
|
61
64
|
let changes = experimentalFlagsEnabled(config).map((s)=>_picocolors.default.yellow(s)).join(", ");
|
|
62
65
|
_log.default.warn("experimental-flags-enabled", [
|
|
63
66
|
`You have enabled experimental features: ${changes}`,
|
|
64
|
-
"Experimental features in Tailwind CSS are not covered by semver, may introduce breaking changes, and can change at any time."
|
|
67
|
+
"Experimental features in Tailwind CSS are not covered by semver, may introduce breaking changes, and can change at any time."
|
|
65
68
|
]);
|
|
66
69
|
}
|
|
67
70
|
}
|
package/lib/index.js
CHANGED
|
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
const _setupTrackingContext = /*#__PURE__*/ _interopRequireDefault(require("./lib/setupTrackingContext"));
|
|
6
6
|
const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("./processTailwindFeatures"));
|
|
7
7
|
const _sharedState = require("./lib/sharedState");
|
|
8
|
+
const _findAtConfigPath = require("./lib/findAtConfigPath");
|
|
8
9
|
function _interopRequireDefault(obj) {
|
|
9
10
|
return obj && obj.__esModule ? obj : {
|
|
10
11
|
default: obj
|
|
@@ -20,6 +21,10 @@ module.exports = function tailwindcss(configOrPath) {
|
|
|
20
21
|
return root;
|
|
21
22
|
},
|
|
22
23
|
function(root, result) {
|
|
24
|
+
var ref;
|
|
25
|
+
// Use the path for the `@config` directive if it exists, otherwise use the
|
|
26
|
+
// path for the file being processed
|
|
27
|
+
configOrPath = (ref = (0, _findAtConfigPath.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : configOrPath;
|
|
23
28
|
let context = (0, _setupTrackingContext.default)(configOrPath);
|
|
24
29
|
if (root.type === "document") {
|
|
25
30
|
let roots = root.nodes.filter((node)=>node.type === "root");
|
|
@@ -36,7 +41,7 @@ module.exports = function tailwindcss(configOrPath) {
|
|
|
36
41
|
console.timeEnd("JIT TOTAL");
|
|
37
42
|
console.log("\n");
|
|
38
43
|
return root;
|
|
39
|
-
}
|
|
44
|
+
}
|
|
40
45
|
].filter(Boolean)
|
|
41
46
|
};
|
|
42
47
|
};
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
function _export(target, all) {
|
|
7
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: all[name]
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
_export(exports, {
|
|
13
|
+
parseCandidateFiles: ()=>parseCandidateFiles,
|
|
14
|
+
resolvedChangedContent: ()=>resolvedChangedContent
|
|
15
|
+
});
|
|
16
|
+
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs"));
|
|
17
|
+
const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
|
|
18
|
+
const _isGlob = /*#__PURE__*/ _interopRequireDefault(require("is-glob"));
|
|
19
|
+
const _fastGlob = /*#__PURE__*/ _interopRequireDefault(require("fast-glob"));
|
|
20
|
+
const _normalizePath = /*#__PURE__*/ _interopRequireDefault(require("normalize-path"));
|
|
21
|
+
const _parseGlob = require("../util/parseGlob");
|
|
22
|
+
const _sharedState = require("./sharedState");
|
|
23
|
+
function _interopRequireDefault(obj) {
|
|
24
|
+
return obj && obj.__esModule ? obj : {
|
|
25
|
+
default: obj
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function parseCandidateFiles(context, tailwindConfig) {
|
|
29
|
+
let files = tailwindConfig.content.files;
|
|
30
|
+
// Normalize the file globs
|
|
31
|
+
files = files.filter((filePath)=>typeof filePath === "string");
|
|
32
|
+
files = files.map(_normalizePath.default);
|
|
33
|
+
// Split into included and excluded globs
|
|
34
|
+
let tasks = _fastGlob.default.generateTasks(files);
|
|
35
|
+
/** @type {ContentPath[]} */ let included = [];
|
|
36
|
+
/** @type {ContentPath[]} */ let excluded = [];
|
|
37
|
+
for (const task of tasks){
|
|
38
|
+
included.push(...task.positive.map((filePath)=>parseFilePath(filePath, false)));
|
|
39
|
+
excluded.push(...task.negative.map((filePath)=>parseFilePath(filePath, true)));
|
|
40
|
+
}
|
|
41
|
+
let paths = [
|
|
42
|
+
...included,
|
|
43
|
+
...excluded
|
|
44
|
+
];
|
|
45
|
+
// Resolve paths relative to the config file or cwd
|
|
46
|
+
paths = resolveRelativePaths(context, paths);
|
|
47
|
+
// Resolve symlinks if possible
|
|
48
|
+
paths = paths.flatMap(resolvePathSymlinks);
|
|
49
|
+
// Update cached patterns
|
|
50
|
+
paths = paths.map(resolveGlobPattern);
|
|
51
|
+
return paths;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
*
|
|
55
|
+
* @param {string} filePath
|
|
56
|
+
* @param {boolean} ignore
|
|
57
|
+
* @returns {ContentPath}
|
|
58
|
+
*/ function parseFilePath(filePath, ignore) {
|
|
59
|
+
let contentPath = {
|
|
60
|
+
original: filePath,
|
|
61
|
+
base: filePath,
|
|
62
|
+
ignore,
|
|
63
|
+
pattern: filePath,
|
|
64
|
+
glob: null
|
|
65
|
+
};
|
|
66
|
+
if ((0, _isGlob.default)(filePath)) {
|
|
67
|
+
Object.assign(contentPath, (0, _parseGlob.parseGlob)(filePath));
|
|
68
|
+
}
|
|
69
|
+
return contentPath;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
*
|
|
73
|
+
* @param {ContentPath} contentPath
|
|
74
|
+
* @returns {ContentPath}
|
|
75
|
+
*/ function resolveGlobPattern(contentPath) {
|
|
76
|
+
contentPath.pattern = contentPath.glob ? `${contentPath.base}/${contentPath.glob}` : contentPath.base;
|
|
77
|
+
contentPath.pattern = contentPath.ignore ? `!${contentPath.pattern}` : contentPath.pattern;
|
|
78
|
+
// This is required for Windows support to properly pick up Glob paths.
|
|
79
|
+
// Afaik, this technically shouldn't be needed but there's probably
|
|
80
|
+
// some internal, direct path matching with a normalized path in
|
|
81
|
+
// a package which can't handle mixed directory separators
|
|
82
|
+
contentPath.pattern = (0, _normalizePath.default)(contentPath.pattern);
|
|
83
|
+
return contentPath;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Resolve each path relative to the config file (when possible) if the experimental flag is enabled
|
|
87
|
+
* Otherwise, resolve relative to the current working directory
|
|
88
|
+
*
|
|
89
|
+
* @param {any} context
|
|
90
|
+
* @param {ContentPath[]} contentPaths
|
|
91
|
+
* @returns {ContentPath[]}
|
|
92
|
+
*/ function resolveRelativePaths(context, contentPaths) {
|
|
93
|
+
let resolveFrom = [];
|
|
94
|
+
// Resolve base paths relative to the config file (when possible) if the experimental flag is enabled
|
|
95
|
+
if (context.userConfigPath && context.tailwindConfig.content.relative) {
|
|
96
|
+
resolveFrom = [
|
|
97
|
+
_path.default.dirname(context.userConfigPath)
|
|
98
|
+
];
|
|
99
|
+
}
|
|
100
|
+
return contentPaths.map((contentPath)=>{
|
|
101
|
+
contentPath.base = _path.default.resolve(...resolveFrom, contentPath.base);
|
|
102
|
+
return contentPath;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the symlink for the base directory / file in each path
|
|
107
|
+
* These are added as additional dependencies to watch for changes because
|
|
108
|
+
* some tools (like webpack) will only watch the actual file or directory
|
|
109
|
+
* but not the symlink itself even in projects that use monorepos.
|
|
110
|
+
*
|
|
111
|
+
* @param {ContentPath} contentPath
|
|
112
|
+
* @returns {ContentPath[]}
|
|
113
|
+
*/ function resolvePathSymlinks(contentPath) {
|
|
114
|
+
let paths = [
|
|
115
|
+
contentPath
|
|
116
|
+
];
|
|
117
|
+
try {
|
|
118
|
+
let resolvedPath = _fs.default.realpathSync(contentPath.base);
|
|
119
|
+
if (resolvedPath !== contentPath.base) {
|
|
120
|
+
paths.push({
|
|
121
|
+
...contentPath,
|
|
122
|
+
base: resolvedPath
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
} catch {
|
|
126
|
+
// TODO: log this?
|
|
127
|
+
}
|
|
128
|
+
return paths;
|
|
129
|
+
}
|
|
130
|
+
function resolvedChangedContent(context, candidateFiles, fileModifiedMap) {
|
|
131
|
+
let changedContent = context.tailwindConfig.content.files.filter((item)=>typeof item.raw === "string").map(({ raw , extension ="html" })=>({
|
|
132
|
+
content: raw,
|
|
133
|
+
extension
|
|
134
|
+
}));
|
|
135
|
+
for (let changedFile of resolveChangedFiles(candidateFiles, fileModifiedMap)){
|
|
136
|
+
let content = _fs.default.readFileSync(changedFile, "utf8");
|
|
137
|
+
let extension = _path.default.extname(changedFile).slice(1);
|
|
138
|
+
changedContent.push({
|
|
139
|
+
content,
|
|
140
|
+
extension
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return changedContent;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
*
|
|
147
|
+
* @param {ContentPath[]} candidateFiles
|
|
148
|
+
* @param {Map<string, number>} fileModifiedMap
|
|
149
|
+
* @returns {Set<string>}
|
|
150
|
+
*/ function resolveChangedFiles(candidateFiles, fileModifiedMap) {
|
|
151
|
+
let paths = candidateFiles.map((contentPath)=>contentPath.pattern);
|
|
152
|
+
let changedFiles = new Set();
|
|
153
|
+
_sharedState.env.DEBUG && console.time("Finding changed files");
|
|
154
|
+
let files = _fastGlob.default.sync(paths, {
|
|
155
|
+
absolute: true
|
|
156
|
+
});
|
|
157
|
+
for (let file of files){
|
|
158
|
+
let prevModified = fileModifiedMap.has(file) ? fileModifiedMap.get(file) : -Infinity;
|
|
159
|
+
let modified = _fs.default.statSync(file).mtimeMs;
|
|
160
|
+
if (modified > prevModified) {
|
|
161
|
+
changedFiles.add(file);
|
|
162
|
+
fileModifiedMap.set(file, modified);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
_sharedState.env.DEBUG && console.timeEnd("Finding changed files");
|
|
166
|
+
return changedFiles;
|
|
167
|
+
}
|
|
@@ -85,7 +85,7 @@ function* buildRegExps(context) {
|
|
|
85
85
|
// Not immediately followed by an `{[(`
|
|
86
86
|
/(?![{([]])/,
|
|
87
87
|
// optionally followed by an opacity modifier
|
|
88
|
-
/(?:\/[^\s'"`\\><$]*)
|
|
88
|
+
/(?:\/[^\s'"`\\><$]*)?/
|
|
89
89
|
]),
|
|
90
90
|
_regex.pattern([
|
|
91
91
|
// Arbitrary values
|
|
@@ -93,16 +93,21 @@ function* buildRegExps(context) {
|
|
|
93
93
|
// Not immediately followed by an `{[(`
|
|
94
94
|
/(?![{([]])/,
|
|
95
95
|
// optionally followed by an opacity modifier
|
|
96
|
-
/(?:\/[^\s'"`\\$]*)
|
|
96
|
+
/(?:\/[^\s'"`\\$]*)?/
|
|
97
97
|
]),
|
|
98
98
|
// Normal values w/o quotes — may include an opacity modifier
|
|
99
|
-
/[-\/][^\s'"`\\$={><]
|
|
100
|
-
]))
|
|
101
|
-
])
|
|
99
|
+
/[-\/][^\s'"`\\$={><]*/
|
|
100
|
+
]))
|
|
101
|
+
])
|
|
102
102
|
]);
|
|
103
103
|
let variantPatterns = [
|
|
104
104
|
// Without quotes
|
|
105
105
|
_regex.any([
|
|
106
|
+
// This is here to provide special support for the `@` variant
|
|
107
|
+
_regex.pattern([
|
|
108
|
+
/@\[[^\s"'`]+\](\/[^\s"'`]+)?/,
|
|
109
|
+
separator
|
|
110
|
+
]),
|
|
106
111
|
_regex.pattern([
|
|
107
112
|
/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/,
|
|
108
113
|
separator
|
|
@@ -110,7 +115,7 @@ function* buildRegExps(context) {
|
|
|
110
115
|
_regex.pattern([
|
|
111
116
|
/[^\s"'`\[\\]+/,
|
|
112
117
|
separator
|
|
113
|
-
])
|
|
118
|
+
])
|
|
114
119
|
]),
|
|
115
120
|
// With quotes allowed
|
|
116
121
|
_regex.any([
|
|
@@ -121,8 +126,8 @@ function* buildRegExps(context) {
|
|
|
121
126
|
_regex.pattern([
|
|
122
127
|
/[^\s`\[\\]+/,
|
|
123
128
|
separator
|
|
124
|
-
])
|
|
125
|
-
])
|
|
129
|
+
])
|
|
130
|
+
])
|
|
126
131
|
];
|
|
127
132
|
for (const variantPattern of variantPatterns){
|
|
128
133
|
yield _regex.pattern([
|
|
@@ -145,8 +150,8 @@ function* buildRegExps(context) {
|
|
|
145
150
|
/\)/
|
|
146
151
|
]),
|
|
147
152
|
// Arbitrary properties, constrained utilities, arbitrary values, etc…
|
|
148
|
-
utility
|
|
149
|
-
]) : utility
|
|
153
|
+
utility
|
|
154
|
+
]) : utility
|
|
150
155
|
]);
|
|
151
156
|
}
|
|
152
157
|
// 5. Inner matches
|
package/lib/lib/detectNesting.js
CHANGED
|
@@ -16,7 +16,7 @@ function _default(_context) {
|
|
|
16
16
|
node.warn(result, [
|
|
17
17
|
"Nested @tailwind rules were detected, but are not supported.",
|
|
18
18
|
"Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix",
|
|
19
|
-
"Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy"
|
|
19
|
+
"Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy"
|
|
20
20
|
].join("\n"));
|
|
21
21
|
return false;
|
|
22
22
|
}
|
|
@@ -28,7 +28,7 @@ function _default(_context) {
|
|
|
28
28
|
nestedRule.warn(result, [
|
|
29
29
|
"Nested CSS was detected, but CSS nesting has not been configured correctly.",
|
|
30
30
|
"Please enable a CSS nesting plugin *before* Tailwind in your configuration.",
|
|
31
|
-
"See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting"
|
|
31
|
+
"See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting"
|
|
32
32
|
].join("\n"));
|
|
33
33
|
return false;
|
|
34
34
|
});
|
|
@@ -15,6 +15,7 @@ const _buildMediaQuery = /*#__PURE__*/ _interopRequireDefault(require("../util/b
|
|
|
15
15
|
const _toPath = require("../util/toPath");
|
|
16
16
|
const _withAlphaVariable = require("../util/withAlphaVariable");
|
|
17
17
|
const _pluginUtils = require("../util/pluginUtils");
|
|
18
|
+
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log"));
|
|
18
19
|
function _interopRequireDefault(obj) {
|
|
19
20
|
return obj && obj.__esModule ? obj : {
|
|
20
21
|
default: obj
|
|
@@ -179,11 +180,26 @@ let nodeTypePropertyMap = {
|
|
|
179
180
|
var ref;
|
|
180
181
|
return (ref = results.find((result)=>result.isValid)) !== null && ref !== void 0 ? ref : results[0];
|
|
181
182
|
}
|
|
182
|
-
function _default(
|
|
183
|
+
function _default(context) {
|
|
184
|
+
let config = context.tailwindConfig;
|
|
183
185
|
let functions = {
|
|
184
186
|
theme: (node, path, ...defaultValue)=>{
|
|
185
187
|
let { isValid , value , error , alpha } = resolvePath(config, path, defaultValue.length ? defaultValue : undefined);
|
|
186
188
|
if (!isValid) {
|
|
189
|
+
var ref;
|
|
190
|
+
let parentNode = node.parent;
|
|
191
|
+
let candidate = (ref = parentNode === null || parentNode === void 0 ? void 0 : parentNode.raws.tailwind) === null || ref === void 0 ? void 0 : ref.candidate;
|
|
192
|
+
if (parentNode && candidate !== undefined) {
|
|
193
|
+
// Remove this utility from any caches
|
|
194
|
+
context.markInvalidUtilityNode(parentNode);
|
|
195
|
+
// Remove the CSS node from the markup
|
|
196
|
+
parentNode.remove();
|
|
197
|
+
// Show a warning
|
|
198
|
+
_log.default.warn("invalid-theme-key-in-class", [
|
|
199
|
+
`The utility \`${candidate}\` contains an invalid theme value and was not generated.`
|
|
200
|
+
]);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
187
203
|
throw node.error(error);
|
|
188
204
|
}
|
|
189
205
|
let maybeColor = (0, _pluginUtils.parseColorFormat)(value);
|
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "default", {
|
|
|
9
9
|
const _postcss = /*#__PURE__*/ _interopRequireDefault(require("postcss"));
|
|
10
10
|
const _postcssSelectorParser = /*#__PURE__*/ _interopRequireDefault(require("postcss-selector-parser"));
|
|
11
11
|
const _generateRules = require("./generateRules");
|
|
12
|
-
const _bigSign = /*#__PURE__*/ _interopRequireDefault(require("../util/bigSign"));
|
|
13
12
|
const _escapeClassName = /*#__PURE__*/ _interopRequireDefault(require("../util/escapeClassName"));
|
|
14
13
|
function _interopRequireDefault(obj) {
|
|
15
14
|
return obj && obj.__esModule ? obj : {
|
|
@@ -41,11 +40,11 @@ function _interopRequireDefault(obj) {
|
|
|
41
40
|
groups: normalizedGroups
|
|
42
41
|
});
|
|
43
42
|
}
|
|
44
|
-
let selectorExtractor = (0, _postcssSelectorParser.default)(
|
|
43
|
+
let selectorExtractor = (0, _postcssSelectorParser.default)();
|
|
45
44
|
/**
|
|
46
45
|
* @param {string} ruleSelectors
|
|
47
46
|
*/ function extractSelectors(ruleSelectors) {
|
|
48
|
-
return selectorExtractor.
|
|
47
|
+
return selectorExtractor.astSync(ruleSelectors);
|
|
49
48
|
}
|
|
50
49
|
function extractBaseCandidates(candidates, separator) {
|
|
51
50
|
let baseClasses = new Set();
|
|
@@ -137,8 +136,7 @@ function* pathToRoot(node) {
|
|
|
137
136
|
* @param {import('postcss').Root} root
|
|
138
137
|
*/ function buildLocalApplyCache(root, context) {
|
|
139
138
|
/** @type {ApplyCache} */ let cache = new Map();
|
|
140
|
-
|
|
141
|
-
root.walkRules((rule, idx)=>{
|
|
139
|
+
root.walkRules((rule)=>{
|
|
142
140
|
// Ignore rules generated by Tailwind
|
|
143
141
|
for (let node of pathToRoot(rule)){
|
|
144
142
|
var ref;
|
|
@@ -148,16 +146,17 @@ function* pathToRoot(node) {
|
|
|
148
146
|
}
|
|
149
147
|
// Clone what's required to represent this singular rule in the tree
|
|
150
148
|
let container = nestedClone(rule);
|
|
149
|
+
let sort = context.offsets.create("user");
|
|
151
150
|
for (let className of extractClasses(rule)){
|
|
152
151
|
let list = cache.get(className) || [];
|
|
153
152
|
cache.set(className, list);
|
|
154
153
|
list.push([
|
|
155
154
|
{
|
|
156
155
|
layer: "user",
|
|
157
|
-
sort
|
|
156
|
+
sort,
|
|
158
157
|
important: false
|
|
159
158
|
},
|
|
160
|
-
container
|
|
159
|
+
container
|
|
161
160
|
]);
|
|
162
161
|
}
|
|
163
162
|
});
|
|
@@ -268,30 +267,64 @@ function processApply(root, context, localCache) {
|
|
|
268
267
|
* What happens in this function is that we prepend a `.` and escape the candidate.
|
|
269
268
|
* This will result in `.hover\:font-bold`
|
|
270
269
|
* Which means that we can replace `.hover\:font-bold` with `.abc` in `.hover\:font-bold:hover` resulting in `.abc:hover`
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
needle.replace(/\\2c /g, "\\,")
|
|
278
|
-
])
|
|
279
|
-
];
|
|
270
|
+
*
|
|
271
|
+
* @param {string} selector
|
|
272
|
+
* @param {string} utilitySelectors
|
|
273
|
+
* @param {string} candidate
|
|
274
|
+
*/ function replaceSelector(selector, utilitySelectors, candidate) {
|
|
275
|
+
let selectorList = extractSelectors(selector);
|
|
280
276
|
let utilitySelectorsList = extractSelectors(utilitySelectors);
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
277
|
+
let candidateList = extractSelectors(`.${(0, _escapeClassName.default)(candidate)}`);
|
|
278
|
+
let candidateClass = candidateList.nodes[0].nodes[0];
|
|
279
|
+
selectorList.each((sel)=>{
|
|
280
|
+
/** @type {Set<import('postcss-selector-parser').Selector>} */ let replaced = new Set();
|
|
281
|
+
utilitySelectorsList.each((utilitySelector)=>{
|
|
282
|
+
let hasReplaced = false;
|
|
283
|
+
utilitySelector = utilitySelector.clone();
|
|
284
|
+
utilitySelector.walkClasses((node)=>{
|
|
285
|
+
if (node.value !== candidateClass.value) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
// Don't replace multiple instances of the same class
|
|
289
|
+
// This is theoretically correct but only partially
|
|
290
|
+
// We'd need to generate every possible permutation of the replacement
|
|
291
|
+
// For example with `.foo + .foo { … }` and `section { @apply foo; }`
|
|
292
|
+
// We'd need to generate all of these:
|
|
293
|
+
// - `.foo + .foo`
|
|
294
|
+
// - `.foo + section`
|
|
295
|
+
// - `section + .foo`
|
|
296
|
+
// - `section + section`
|
|
297
|
+
if (hasReplaced) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
// Since you can only `@apply` class names this is sufficient
|
|
301
|
+
// We want to replace the matched class name with the selector the user is using
|
|
302
|
+
// Ex: Replace `.text-blue-500` with `.foo.bar:is(.something-cool)`
|
|
303
|
+
node.replaceWith(...sel.nodes.map((node)=>node.clone()));
|
|
304
|
+
// Record that we did something and we want to use this new selector
|
|
305
|
+
replaced.add(utilitySelector);
|
|
306
|
+
hasReplaced = true;
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
// Sort tag names before class names
|
|
310
|
+
// This happens when replacing `.bar` in `.foo.bar` with a tag like `section`
|
|
311
|
+
for (const sel1 of replaced){
|
|
312
|
+
sel1.sort((a, b)=>{
|
|
313
|
+
if (a.type === "tag" && b.type === "class") {
|
|
314
|
+
return -1;
|
|
315
|
+
} else if (a.type === "class" && b.type === "tag") {
|
|
316
|
+
return 1;
|
|
317
|
+
} else if (a.type === "class" && b.type === "pseudo") {
|
|
318
|
+
return -1;
|
|
319
|
+
} else if (a.type === "pseudo" && b.type === "class") {
|
|
320
|
+
return 1;
|
|
321
|
+
}
|
|
322
|
+
return sel1.index(a) - sel1.index(b);
|
|
323
|
+
});
|
|
292
324
|
}
|
|
293
|
-
|
|
294
|
-
})
|
|
325
|
+
sel.replaceWith(...replaced);
|
|
326
|
+
});
|
|
327
|
+
return selectorList.toString();
|
|
295
328
|
}
|
|
296
329
|
let perParentApplies = new Map();
|
|
297
330
|
// Collect all apply candidates and their rules
|
|
@@ -338,7 +371,7 @@ function processApply(root, context, localCache) {
|
|
|
338
371
|
applyCandidate1,
|
|
339
372
|
...extractBaseCandidates([
|
|
340
373
|
applyCandidate1
|
|
341
|
-
], context.tailwindConfig.separator)
|
|
374
|
+
], context.tailwindConfig.separator)
|
|
342
375
|
];
|
|
343
376
|
for (let [meta, node] of rules1){
|
|
344
377
|
let parentClasses = extractClasses(parent);
|
|
@@ -443,17 +476,13 @@ function processApply(root, context, localCache) {
|
|
|
443
476
|
}
|
|
444
477
|
// Insert it
|
|
445
478
|
siblings.push([
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
...meta,
|
|
449
|
-
sort: meta.sort | context.layerOrder[meta.layer]
|
|
450
|
-
},
|
|
451
|
-
root1.nodes[0],
|
|
479
|
+
meta.sort,
|
|
480
|
+
root1.nodes[0]
|
|
452
481
|
]);
|
|
453
482
|
}
|
|
454
483
|
}
|
|
455
484
|
// Inject the rules, sorted, correctly
|
|
456
|
-
let nodes =
|
|
485
|
+
let nodes = context.offsets.sort(siblings).map((s)=>s[1]);
|
|
457
486
|
// `parent` refers to the node at `.abc` in: .abc { @apply mt-2 }
|
|
458
487
|
parent.after(nodes);
|
|
459
488
|
}
|
|
@@ -9,7 +9,6 @@ Object.defineProperty(exports, "default", {
|
|
|
9
9
|
const _quickLru = /*#__PURE__*/ _interopRequireDefault(require("quick-lru"));
|
|
10
10
|
const _sharedState = /*#__PURE__*/ _interopRequireWildcard(require("./sharedState"));
|
|
11
11
|
const _generateRules = require("./generateRules");
|
|
12
|
-
const _bigSign = /*#__PURE__*/ _interopRequireDefault(require("../util/bigSign"));
|
|
13
12
|
const _log = /*#__PURE__*/ _interopRequireDefault(require("../util/log"));
|
|
14
13
|
const _cloneNodes = /*#__PURE__*/ _interopRequireDefault(require("../util/cloneNodes"));
|
|
15
14
|
const _defaultExtractor = require("./defaultExtractor");
|
|
@@ -103,49 +102,21 @@ function getClassCandidates(content, extractor, candidates, seen) {
|
|
|
103
102
|
}
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
/**
|
|
106
|
+
*
|
|
107
|
+
* @param {[import('./offsets.js').RuleOffset, import('postcss').Node][]} rules
|
|
108
|
+
* @param {*} context
|
|
109
|
+
*/ function buildStylesheet(rules, context) {
|
|
110
|
+
let sortedRules = context.offsets.sort(rules);
|
|
108
111
|
let returnValue = {
|
|
109
112
|
base: new Set(),
|
|
110
113
|
defaults: new Set(),
|
|
111
114
|
components: new Set(),
|
|
112
115
|
utilities: new Set(),
|
|
113
|
-
variants: new Set()
|
|
114
|
-
// All the CSS that is not Tailwind related can be put in this bucket. This
|
|
115
|
-
// will make it easier to later use this information when we want to
|
|
116
|
-
// `@apply` for example. The main reason we do this here is because we
|
|
117
|
-
// still need to make sure the order is correct. Last but not least, we
|
|
118
|
-
// will make sure to always re-inject this section into the css, even if
|
|
119
|
-
// certain rules were not used. This means that it will look like a no-op
|
|
120
|
-
// from the user's perspective, but we gathered all the useful information
|
|
121
|
-
// we need.
|
|
122
|
-
user: new Set()
|
|
116
|
+
variants: new Set()
|
|
123
117
|
};
|
|
124
118
|
for (let [sort, rule] of sortedRules){
|
|
125
|
-
|
|
126
|
-
returnValue.variants.add(rule);
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
if (sort & context.layerOrder.base) {
|
|
130
|
-
returnValue.base.add(rule);
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
if (sort & context.layerOrder.defaults) {
|
|
134
|
-
returnValue.defaults.add(rule);
|
|
135
|
-
continue;
|
|
136
|
-
}
|
|
137
|
-
if (sort & context.layerOrder.components) {
|
|
138
|
-
returnValue.components.add(rule);
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (sort & context.layerOrder.utilities) {
|
|
142
|
-
returnValue.utilities.add(rule);
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
145
|
-
if (sort & context.layerOrder.user) {
|
|
146
|
-
returnValue.user.add(rule);
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
119
|
+
returnValue[sort.layer].add(rule);
|
|
149
120
|
}
|
|
150
121
|
return returnValue;
|
|
151
122
|
}
|
|
@@ -188,14 +159,11 @@ function expandTailwindAtRules(context) {
|
|
|
188
159
|
// Generate the actual CSS
|
|
189
160
|
let classCacheCount = context.classCache.size;
|
|
190
161
|
env.DEBUG && console.time("Generate rules");
|
|
191
|
-
|
|
162
|
+
(0, _generateRules.generateRules)(candidates, context);
|
|
192
163
|
env.DEBUG && console.timeEnd("Generate rules");
|
|
193
164
|
// We only ever add to the classCache, so if it didn't grow, there is nothing new.
|
|
194
165
|
env.DEBUG && console.time("Build stylesheet");
|
|
195
166
|
if (context.stylesheetCache === null || context.classCache.size !== classCacheCount) {
|
|
196
|
-
for (let rule of rules){
|
|
197
|
-
context.ruleCache.add(rule);
|
|
198
|
-
}
|
|
199
167
|
context.stylesheetCache = buildStylesheet([
|
|
200
168
|
...context.ruleCache
|
|
201
169
|
], context);
|
|
@@ -259,7 +227,7 @@ function expandTailwindAtRules(context) {
|
|
|
259
227
|
if (layerNodes.utilities && utilityNodes.size === 0 && !hasUtilityVariants) {
|
|
260
228
|
_log.default.warn("content-problems", [
|
|
261
229
|
"No utility classes were detected in your source files. If this is unexpected, double-check the `content` option in your Tailwind CSS configuration.",
|
|
262
|
-
"https://tailwindcss.com/docs/content-configuration"
|
|
230
|
+
"https://tailwindcss.com/docs/content-configuration"
|
|
263
231
|
]);
|
|
264
232
|
}
|
|
265
233
|
// ---
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "findAtConfigPath", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: ()=>findAtConfigPath
|
|
8
|
+
});
|
|
9
|
+
const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs"));
|
|
10
|
+
const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
|
|
11
|
+
function _interopRequireDefault(obj) {
|
|
12
|
+
return obj && obj.__esModule ? obj : {
|
|
13
|
+
default: obj
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function findAtConfigPath(root, result) {
|
|
17
|
+
let configPath = null;
|
|
18
|
+
let relativeTo = null;
|
|
19
|
+
root.walkAtRules("config", (rule)=>{
|
|
20
|
+
var ref;
|
|
21
|
+
var _file, ref1;
|
|
22
|
+
relativeTo = (ref1 = (_file = (ref = rule.source) === null || ref === void 0 ? void 0 : ref.input.file) !== null && _file !== void 0 ? _file : result.opts.from) !== null && ref1 !== void 0 ? ref1 : null;
|
|
23
|
+
if (relativeTo === null) {
|
|
24
|
+
throw rule.error("The `@config` directive cannot be used without setting `from` in your PostCSS config.");
|
|
25
|
+
}
|
|
26
|
+
if (configPath) {
|
|
27
|
+
throw rule.error("Only one `@config` directive is allowed per file.");
|
|
28
|
+
}
|
|
29
|
+
let matches = rule.params.match(/(['"])(.*?)\1/);
|
|
30
|
+
if (!matches) {
|
|
31
|
+
throw rule.error("A path is required when using the `@config` directive.");
|
|
32
|
+
}
|
|
33
|
+
let inputPath = matches[2];
|
|
34
|
+
if (_path.default.isAbsolute(inputPath)) {
|
|
35
|
+
throw rule.error("The `@config` directive cannot be used with an absolute path.");
|
|
36
|
+
}
|
|
37
|
+
configPath = _path.default.resolve(_path.default.dirname(relativeTo), inputPath);
|
|
38
|
+
if (!_fs.default.existsSync(configPath)) {
|
|
39
|
+
throw rule.error(`The config file at "${inputPath}" does not exist. Make sure the path is correct and the file exists.`);
|
|
40
|
+
}
|
|
41
|
+
rule.remove();
|
|
42
|
+
});
|
|
43
|
+
return configPath ? configPath : null;
|
|
44
|
+
}
|