tailwindcss 3.2.4 → 3.2.5
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 +44 -1
- package/README.md +1 -1
- package/lib/cli/build/index.js +5 -1
- package/lib/cli/build/plugin.js +39 -34
- package/lib/cli/index.js +231 -10
- package/lib/cli/init/index.js +2 -2
- package/lib/cli.js +4 -226
- package/lib/corePlugins.js +45 -27
- package/lib/featureFlags.js +8 -8
- package/lib/index.js +4 -46
- package/lib/lib/collapseAdjacentRules.js +2 -2
- package/lib/lib/collapseDuplicateDeclarations.js +2 -2
- package/lib/lib/content.js +16 -16
- package/lib/lib/defaultExtractor.js +10 -5
- package/lib/lib/detectNesting.js +7 -1
- package/lib/lib/evaluateTailwindFunctions.js +4 -4
- package/lib/lib/expandApplyAtRules.js +2 -2
- package/lib/lib/expandTailwindAtRules.js +35 -9
- package/lib/lib/findAtConfigPath.js +3 -3
- package/lib/lib/generateRules.js +105 -50
- package/lib/lib/offsets.js +88 -1
- package/lib/lib/remap-bitfield.js +87 -0
- package/lib/lib/resolveDefaultsAtRules.js +4 -4
- package/lib/lib/setupContextUtils.js +121 -80
- package/lib/lib/setupTrackingContext.js +25 -4
- package/lib/lib/sharedState.js +19 -1
- package/lib/oxide/cli/build/deps.js +81 -0
- package/lib/oxide/cli/build/index.js +47 -0
- package/lib/oxide/cli/build/plugin.js +364 -0
- package/lib/oxide/cli/build/utils.js +77 -0
- package/lib/oxide/cli/build/watching.js +177 -0
- package/lib/oxide/cli/help/index.js +70 -0
- package/lib/oxide/cli/index.js +220 -0
- package/lib/oxide/cli/init/index.js +35 -0
- package/lib/oxide/cli.js +5 -0
- package/lib/oxide/postcss-plugin.js +2 -0
- package/lib/plugin.js +98 -0
- package/lib/postcss-plugins/nesting/plugin.js +2 -2
- package/lib/util/cloneNodes.js +2 -2
- package/lib/util/color.js +20 -6
- package/lib/util/createUtilityPlugin.js +2 -2
- package/lib/util/dataTypes.js +26 -2
- package/lib/util/defaults.js +4 -4
- package/lib/util/escapeClassName.js +3 -3
- package/lib/util/formatVariantSelector.js +171 -105
- package/lib/util/getAllConfigs.js +2 -2
- package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +2 -2
- package/lib/util/negateValue.js +2 -2
- package/lib/util/normalizeConfig.js +22 -22
- package/lib/util/pluginUtils.js +38 -40
- package/lib/util/prefixSelector.js +22 -8
- package/lib/util/resolveConfig.js +8 -10
- package/oxide-node-api-shim/index.js +21 -0
- package/oxide-node-api-shim/package.json +5 -0
- package/package.json +32 -19
- package/peers/index.js +61 -42
- package/resolveConfig.d.ts +11 -2
- package/scripts/swap-engines.js +40 -0
- package/src/cli/build/index.js +6 -2
- package/src/cli/build/plugin.js +14 -9
- package/src/cli/index.js +234 -3
- package/src/cli.js +4 -220
- package/src/corePlugins.js +31 -3
- package/src/index.js +4 -46
- package/src/lib/content.js +12 -17
- package/src/lib/defaultExtractor.js +9 -3
- package/src/lib/detectNesting.js +9 -1
- package/src/lib/expandTailwindAtRules.js +37 -6
- package/src/lib/generateRules.js +90 -28
- package/src/lib/offsets.js +104 -1
- package/src/lib/remap-bitfield.js +82 -0
- package/src/lib/setupContextUtils.js +97 -55
- package/src/lib/setupTrackingContext.js +31 -6
- package/src/lib/sharedState.js +17 -0
- package/src/oxide/cli/build/deps.ts +91 -0
- package/src/oxide/cli/build/index.ts +47 -0
- package/src/oxide/cli/build/plugin.ts +436 -0
- package/src/oxide/cli/build/utils.ts +74 -0
- package/src/oxide/cli/build/watching.ts +225 -0
- package/src/oxide/cli/help/index.ts +69 -0
- package/src/oxide/cli/index.ts +212 -0
- package/src/oxide/cli/init/index.ts +32 -0
- package/src/oxide/cli.ts +1 -0
- package/src/oxide/postcss-plugin.ts +1 -0
- package/src/plugin.js +107 -0
- package/src/util/color.js +17 -2
- package/src/util/dataTypes.js +29 -4
- package/src/util/formatVariantSelector.js +215 -122
- package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
- package/src/util/negateValue.js +1 -1
- package/src/util/pluginUtils.js +22 -19
- package/src/util/prefixSelector.js +28 -10
- package/src/util/resolveConfig.js +0 -2
- package/stubs/defaultConfig.stub.js +149 -165
- package/types/config.d.ts +7 -2
- package/types/generated/default-theme.d.ts +77 -77
- package/lib/cli/shared.js +0 -12
- package/scripts/install-integrations.js +0 -27
- package/scripts/rebuildFixtures.js +0 -68
- package/src/cli/shared.js +0 -5
package/src/cli/index.js
CHANGED
|
@@ -1,3 +1,234 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import arg from 'arg'
|
|
5
|
+
import fs from 'fs'
|
|
6
|
+
|
|
7
|
+
import { build } from './build'
|
|
8
|
+
import { help } from './help'
|
|
9
|
+
import { init } from './init'
|
|
10
|
+
|
|
11
|
+
function isESM() {
|
|
12
|
+
const pkgPath = path.resolve('./package.json')
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
|
16
|
+
return pkg.type && pkg.type === 'module'
|
|
17
|
+
} catch (err) {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
let configs = isESM()
|
|
23
|
+
? {
|
|
24
|
+
tailwind: 'tailwind.config.cjs',
|
|
25
|
+
postcss: 'postcss.config.cjs',
|
|
26
|
+
}
|
|
27
|
+
: {
|
|
28
|
+
tailwind: 'tailwind.config.js',
|
|
29
|
+
postcss: 'postcss.config.js',
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---
|
|
33
|
+
|
|
34
|
+
function oneOf(...options) {
|
|
35
|
+
return Object.assign(
|
|
36
|
+
(value = true) => {
|
|
37
|
+
for (let option of options) {
|
|
38
|
+
let parsed = option(value)
|
|
39
|
+
if (parsed === value) {
|
|
40
|
+
return parsed
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw new Error('...')
|
|
45
|
+
},
|
|
46
|
+
{ manualParsing: true }
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let commands = {
|
|
51
|
+
init: {
|
|
52
|
+
run: init,
|
|
53
|
+
args: {
|
|
54
|
+
'--full': { type: Boolean, description: `Initialize a full \`${configs.tailwind}\` file` },
|
|
55
|
+
'--postcss': { type: Boolean, description: `Initialize a \`${configs.postcss}\` file` },
|
|
56
|
+
'-f': '--full',
|
|
57
|
+
'-p': '--postcss',
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
build: {
|
|
61
|
+
run: build,
|
|
62
|
+
args: {
|
|
63
|
+
'--input': { type: String, description: 'Input file' },
|
|
64
|
+
'--output': { type: String, description: 'Output file' },
|
|
65
|
+
'--watch': {
|
|
66
|
+
type: oneOf(String, Boolean),
|
|
67
|
+
description: 'Watch for changes and rebuild as needed',
|
|
68
|
+
},
|
|
69
|
+
'--poll': {
|
|
70
|
+
type: Boolean,
|
|
71
|
+
description: 'Use polling instead of filesystem events when watching',
|
|
72
|
+
},
|
|
73
|
+
'--content': {
|
|
74
|
+
type: String,
|
|
75
|
+
description: 'Content paths to use for removing unused classes',
|
|
76
|
+
},
|
|
77
|
+
'--purge': {
|
|
78
|
+
type: String,
|
|
79
|
+
deprecated: true,
|
|
80
|
+
},
|
|
81
|
+
'--postcss': {
|
|
82
|
+
type: oneOf(String, Boolean),
|
|
83
|
+
description: 'Load custom PostCSS configuration',
|
|
84
|
+
},
|
|
85
|
+
'--minify': { type: Boolean, description: 'Minify the output' },
|
|
86
|
+
'--config': {
|
|
87
|
+
type: String,
|
|
88
|
+
description: 'Path to a custom config file',
|
|
89
|
+
},
|
|
90
|
+
'--no-autoprefixer': {
|
|
91
|
+
type: Boolean,
|
|
92
|
+
description: 'Disable autoprefixer',
|
|
93
|
+
},
|
|
94
|
+
'-c': '--config',
|
|
95
|
+
'-i': '--input',
|
|
96
|
+
'-o': '--output',
|
|
97
|
+
'-m': '--minify',
|
|
98
|
+
'-w': '--watch',
|
|
99
|
+
'-p': '--poll',
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
let sharedFlags = {
|
|
105
|
+
'--help': { type: Boolean, description: 'Display usage information' },
|
|
106
|
+
'-h': '--help',
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (
|
|
110
|
+
process.stdout.isTTY /* Detect redirecting output to a file */ &&
|
|
111
|
+
(process.argv[2] === undefined ||
|
|
112
|
+
process.argv.slice(2).every((flag) => sharedFlags[flag] !== undefined))
|
|
113
|
+
) {
|
|
114
|
+
help({
|
|
115
|
+
usage: [
|
|
116
|
+
'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]',
|
|
117
|
+
'tailwindcss init [--full] [--postcss] [options...]',
|
|
118
|
+
],
|
|
119
|
+
commands: Object.keys(commands)
|
|
120
|
+
.filter((command) => command !== 'build')
|
|
121
|
+
.map((command) => `${command} [options]`),
|
|
122
|
+
options: { ...commands.build.args, ...sharedFlags },
|
|
123
|
+
})
|
|
124
|
+
process.exit(0)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let command = ((arg = '') => (arg.startsWith('-') ? undefined : arg))(process.argv[2]) || 'build'
|
|
128
|
+
|
|
129
|
+
if (commands[command] === undefined) {
|
|
130
|
+
if (fs.existsSync(path.resolve(command))) {
|
|
131
|
+
// TODO: Deprecate this in future versions
|
|
132
|
+
// Check if non-existing command, might be a file.
|
|
133
|
+
command = 'build'
|
|
134
|
+
} else {
|
|
135
|
+
help({
|
|
136
|
+
message: `Invalid command: ${command}`,
|
|
137
|
+
usage: ['tailwindcss <command> [options]'],
|
|
138
|
+
commands: Object.keys(commands)
|
|
139
|
+
.filter((command) => command !== 'build')
|
|
140
|
+
.map((command) => `${command} [options]`),
|
|
141
|
+
options: sharedFlags,
|
|
142
|
+
})
|
|
143
|
+
process.exit(1)
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Execute command
|
|
148
|
+
let { args: flags, run } = commands[command]
|
|
149
|
+
let args = (() => {
|
|
150
|
+
try {
|
|
151
|
+
let result = arg(
|
|
152
|
+
Object.fromEntries(
|
|
153
|
+
Object.entries({ ...flags, ...sharedFlags })
|
|
154
|
+
.filter(([_key, value]) => !value?.type?.manualParsing)
|
|
155
|
+
.map(([key, value]) => [key, typeof value === 'object' ? value.type : value])
|
|
156
|
+
),
|
|
157
|
+
{ permissive: true }
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String)
|
|
161
|
+
for (let i = result['_'].length - 1; i >= 0; --i) {
|
|
162
|
+
let flag = result['_'][i]
|
|
163
|
+
if (!flag.startsWith('-')) continue
|
|
164
|
+
|
|
165
|
+
let [flagName, flagValue] = flag.split('=')
|
|
166
|
+
let handler = flags[flagName]
|
|
167
|
+
|
|
168
|
+
// Resolve flagName & handler
|
|
169
|
+
while (typeof handler === 'string') {
|
|
170
|
+
flagName = handler
|
|
171
|
+
handler = flags[handler]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (!handler) continue
|
|
175
|
+
|
|
176
|
+
let args = []
|
|
177
|
+
let offset = i + 1
|
|
178
|
+
|
|
179
|
+
// --flag value syntax was used so we need to pull `value` from `args`
|
|
180
|
+
if (flagValue === undefined) {
|
|
181
|
+
// Parse args for current flag
|
|
182
|
+
while (result['_'][offset] && !result['_'][offset].startsWith('-')) {
|
|
183
|
+
args.push(result['_'][offset++])
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Cleanup manually parsed flags + args
|
|
187
|
+
result['_'].splice(i, 1 + args.length)
|
|
188
|
+
|
|
189
|
+
// No args were provided, use default value defined in handler
|
|
190
|
+
// One arg was provided, use that directly
|
|
191
|
+
// Multiple args were provided so pass them all in an array
|
|
192
|
+
flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args
|
|
193
|
+
} else {
|
|
194
|
+
// Remove the whole flag from the args array
|
|
195
|
+
result['_'].splice(i, 1)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Set the resolved value in the `result` object
|
|
199
|
+
result[flagName] = handler.type(flagValue, flagName)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Ensure that the `command` is always the first argument in the `args`.
|
|
203
|
+
// This is important so that we don't have to check if a default command
|
|
204
|
+
// (build) was used or not from within each plugin.
|
|
205
|
+
//
|
|
206
|
+
// E.g.: tailwindcss input.css -> _: ['build', 'input.css']
|
|
207
|
+
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css']
|
|
208
|
+
if (result['_'][0] !== command) {
|
|
209
|
+
result['_'].unshift(command)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return result
|
|
213
|
+
} catch (err) {
|
|
214
|
+
if (err.code === 'ARG_UNKNOWN_OPTION') {
|
|
215
|
+
help({
|
|
216
|
+
message: err.message,
|
|
217
|
+
usage: ['tailwindcss <command> [options]'],
|
|
218
|
+
options: sharedFlags,
|
|
219
|
+
})
|
|
220
|
+
process.exit(1)
|
|
221
|
+
}
|
|
222
|
+
throw err
|
|
223
|
+
}
|
|
224
|
+
})()
|
|
225
|
+
|
|
226
|
+
if (args['--help']) {
|
|
227
|
+
help({
|
|
228
|
+
options: { ...flags, ...sharedFlags },
|
|
229
|
+
usage: [`tailwindcss ${command} [options]`],
|
|
230
|
+
})
|
|
231
|
+
process.exit(0)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
run(args, configs)
|
package/src/cli.js
CHANGED
|
@@ -1,223 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { build } from './cli/build'
|
|
8
|
-
import { help } from './cli/help'
|
|
9
|
-
import { init } from './cli/init'
|
|
10
|
-
|
|
11
|
-
function isESM() {
|
|
12
|
-
const pkgPath = path.resolve('./package.json')
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'))
|
|
16
|
-
return pkg.type && pkg.type === 'module'
|
|
17
|
-
} catch (err) {
|
|
18
|
-
return false
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
let configs = isESM()
|
|
23
|
-
? {
|
|
24
|
-
tailwind: 'tailwind.config.cjs',
|
|
25
|
-
postcss: 'postcss.config.cjs',
|
|
26
|
-
}
|
|
27
|
-
: {
|
|
28
|
-
tailwind: 'tailwind.config.js',
|
|
29
|
-
postcss: 'postcss.config.js',
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// ---
|
|
33
|
-
|
|
34
|
-
function oneOf(...options) {
|
|
35
|
-
return Object.assign(
|
|
36
|
-
(value = true) => {
|
|
37
|
-
for (let option of options) {
|
|
38
|
-
let parsed = option(value)
|
|
39
|
-
if (parsed === value) {
|
|
40
|
-
return parsed
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
throw new Error('...')
|
|
45
|
-
},
|
|
46
|
-
{ manualParsing: true }
|
|
47
|
-
)
|
|
3
|
+
if (process.env.OXIDE) {
|
|
4
|
+
module.exports = require('./oxide/cli')
|
|
5
|
+
} else {
|
|
6
|
+
module.exports = require('./cli/index')
|
|
48
7
|
}
|
|
49
|
-
|
|
50
|
-
let commands = {
|
|
51
|
-
init: {
|
|
52
|
-
run: init,
|
|
53
|
-
args: {
|
|
54
|
-
'--full': { type: Boolean, description: `Initialize a full \`${configs.tailwind}\` file` },
|
|
55
|
-
'--postcss': { type: Boolean, description: `Initialize a \`${configs.postcss}\` file` },
|
|
56
|
-
'-f': '--full',
|
|
57
|
-
'-p': '--postcss',
|
|
58
|
-
},
|
|
59
|
-
},
|
|
60
|
-
build: {
|
|
61
|
-
run: build,
|
|
62
|
-
args: {
|
|
63
|
-
'--input': { type: String, description: 'Input file' },
|
|
64
|
-
'--output': { type: String, description: 'Output file' },
|
|
65
|
-
'--watch': { type: Boolean, description: 'Watch for changes and rebuild as needed' },
|
|
66
|
-
'--poll': {
|
|
67
|
-
type: Boolean,
|
|
68
|
-
description: 'Use polling instead of filesystem events when watching',
|
|
69
|
-
},
|
|
70
|
-
'--content': {
|
|
71
|
-
type: String,
|
|
72
|
-
description: 'Content paths to use for removing unused classes',
|
|
73
|
-
},
|
|
74
|
-
'--purge': {
|
|
75
|
-
type: String,
|
|
76
|
-
deprecated: true,
|
|
77
|
-
},
|
|
78
|
-
'--postcss': {
|
|
79
|
-
type: oneOf(String, Boolean),
|
|
80
|
-
description: 'Load custom PostCSS configuration',
|
|
81
|
-
},
|
|
82
|
-
'--minify': { type: Boolean, description: 'Minify the output' },
|
|
83
|
-
'--config': {
|
|
84
|
-
type: String,
|
|
85
|
-
description: 'Path to a custom config file',
|
|
86
|
-
},
|
|
87
|
-
'--no-autoprefixer': {
|
|
88
|
-
type: Boolean,
|
|
89
|
-
description: 'Disable autoprefixer',
|
|
90
|
-
},
|
|
91
|
-
'-c': '--config',
|
|
92
|
-
'-i': '--input',
|
|
93
|
-
'-o': '--output',
|
|
94
|
-
'-m': '--minify',
|
|
95
|
-
'-w': '--watch',
|
|
96
|
-
'-p': '--poll',
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
let sharedFlags = {
|
|
102
|
-
'--help': { type: Boolean, description: 'Display usage information' },
|
|
103
|
-
'-h': '--help',
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (
|
|
107
|
-
process.stdout.isTTY /* Detect redirecting output to a file */ &&
|
|
108
|
-
(process.argv[2] === undefined ||
|
|
109
|
-
process.argv.slice(2).every((flag) => sharedFlags[flag] !== undefined))
|
|
110
|
-
) {
|
|
111
|
-
help({
|
|
112
|
-
usage: [
|
|
113
|
-
'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]',
|
|
114
|
-
'tailwindcss init [--full] [--postcss] [options...]',
|
|
115
|
-
],
|
|
116
|
-
commands: Object.keys(commands)
|
|
117
|
-
.filter((command) => command !== 'build')
|
|
118
|
-
.map((command) => `${command} [options]`),
|
|
119
|
-
options: { ...commands.build.args, ...sharedFlags },
|
|
120
|
-
})
|
|
121
|
-
process.exit(0)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
let command = ((arg = '') => (arg.startsWith('-') ? undefined : arg))(process.argv[2]) || 'build'
|
|
125
|
-
|
|
126
|
-
if (commands[command] === undefined) {
|
|
127
|
-
if (fs.existsSync(path.resolve(command))) {
|
|
128
|
-
// TODO: Deprecate this in future versions
|
|
129
|
-
// Check if non-existing command, might be a file.
|
|
130
|
-
command = 'build'
|
|
131
|
-
} else {
|
|
132
|
-
help({
|
|
133
|
-
message: `Invalid command: ${command}`,
|
|
134
|
-
usage: ['tailwindcss <command> [options]'],
|
|
135
|
-
commands: Object.keys(commands)
|
|
136
|
-
.filter((command) => command !== 'build')
|
|
137
|
-
.map((command) => `${command} [options]`),
|
|
138
|
-
options: sharedFlags,
|
|
139
|
-
})
|
|
140
|
-
process.exit(1)
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Execute command
|
|
145
|
-
let { args: flags, run } = commands[command]
|
|
146
|
-
let args = (() => {
|
|
147
|
-
try {
|
|
148
|
-
let result = arg(
|
|
149
|
-
Object.fromEntries(
|
|
150
|
-
Object.entries({ ...flags, ...sharedFlags })
|
|
151
|
-
.filter(([_key, value]) => !value?.type?.manualParsing)
|
|
152
|
-
.map(([key, value]) => [key, typeof value === 'object' ? value.type : value])
|
|
153
|
-
),
|
|
154
|
-
{ permissive: true }
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
// Manual parsing of flags to allow for special flags like oneOf(Boolean, String)
|
|
158
|
-
for (let i = result['_'].length - 1; i >= 0; --i) {
|
|
159
|
-
let flag = result['_'][i]
|
|
160
|
-
if (!flag.startsWith('-')) continue
|
|
161
|
-
|
|
162
|
-
let flagName = flag
|
|
163
|
-
let handler = flags[flag]
|
|
164
|
-
|
|
165
|
-
// Resolve flagName & handler
|
|
166
|
-
while (typeof handler === 'string') {
|
|
167
|
-
flagName = handler
|
|
168
|
-
handler = flags[handler]
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
if (!handler) continue
|
|
172
|
-
|
|
173
|
-
let args = []
|
|
174
|
-
let offset = i + 1
|
|
175
|
-
|
|
176
|
-
// Parse args for current flag
|
|
177
|
-
while (result['_'][offset] && !result['_'][offset].startsWith('-')) {
|
|
178
|
-
args.push(result['_'][offset++])
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
// Cleanup manually parsed flags + args
|
|
182
|
-
result['_'].splice(i, 1 + args.length)
|
|
183
|
-
|
|
184
|
-
// Set the resolved value in the `result` object
|
|
185
|
-
result[flagName] = handler.type(
|
|
186
|
-
args.length === 0 ? undefined : args.length === 1 ? args[0] : args,
|
|
187
|
-
flagName
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// Ensure that the `command` is always the first argument in the `args`.
|
|
192
|
-
// This is important so that we don't have to check if a default command
|
|
193
|
-
// (build) was used or not from within each plugin.
|
|
194
|
-
//
|
|
195
|
-
// E.g.: tailwindcss input.css -> _: ['build', 'input.css']
|
|
196
|
-
// E.g.: tailwindcss build input.css -> _: ['build', 'input.css']
|
|
197
|
-
if (result['_'][0] !== command) {
|
|
198
|
-
result['_'].unshift(command)
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
return result
|
|
202
|
-
} catch (err) {
|
|
203
|
-
if (err.code === 'ARG_UNKNOWN_OPTION') {
|
|
204
|
-
help({
|
|
205
|
-
message: err.message,
|
|
206
|
-
usage: ['tailwindcss <command> [options]'],
|
|
207
|
-
options: sharedFlags,
|
|
208
|
-
})
|
|
209
|
-
process.exit(1)
|
|
210
|
-
}
|
|
211
|
-
throw err
|
|
212
|
-
}
|
|
213
|
-
})()
|
|
214
|
-
|
|
215
|
-
if (args['--help']) {
|
|
216
|
-
help({
|
|
217
|
-
options: { ...flags, ...sharedFlags },
|
|
218
|
-
usage: [`tailwindcss ${command} [options]`],
|
|
219
|
-
})
|
|
220
|
-
process.exit(0)
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
run(args, configs)
|
package/src/corePlugins.js
CHANGED
|
@@ -150,9 +150,13 @@ export let variantPlugins = {
|
|
|
150
150
|
|
|
151
151
|
let variants = {
|
|
152
152
|
group: (_, { modifier }) =>
|
|
153
|
-
modifier
|
|
153
|
+
modifier
|
|
154
|
+
? [`:merge(.group\\/${escapeClassName(modifier)})`, ' &']
|
|
155
|
+
: [`:merge(.group)`, ' &'],
|
|
154
156
|
peer: (_, { modifier }) =>
|
|
155
|
-
modifier
|
|
157
|
+
modifier
|
|
158
|
+
? [`:merge(.peer\\/${escapeClassName(modifier)})`, ' ~ &']
|
|
159
|
+
: [`:merge(.peer)`, ' ~ &'],
|
|
156
160
|
}
|
|
157
161
|
|
|
158
162
|
for (let [name, fn] of Object.entries(variants)) {
|
|
@@ -163,7 +167,30 @@ export let variantPlugins = {
|
|
|
163
167
|
if (!result.includes('&')) result = '&' + result
|
|
164
168
|
|
|
165
169
|
let [a, b] = fn('', extra)
|
|
166
|
-
|
|
170
|
+
|
|
171
|
+
let start = null
|
|
172
|
+
let end = null
|
|
173
|
+
let quotes = 0
|
|
174
|
+
|
|
175
|
+
for (let i = 0; i < result.length; ++i) {
|
|
176
|
+
let c = result[i]
|
|
177
|
+
if (c === '&') {
|
|
178
|
+
start = i
|
|
179
|
+
} else if (c === "'" || c === '"') {
|
|
180
|
+
quotes += 1
|
|
181
|
+
} else if (start !== null && c === ' ' && !quotes) {
|
|
182
|
+
end = i
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (start !== null && end === null) {
|
|
187
|
+
end = result.length
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Basically this but can handle quotes:
|
|
191
|
+
// result.replace(/&(\S+)?/g, (_, pseudo = '') => a + pseudo + b)
|
|
192
|
+
|
|
193
|
+
return result.slice(0, start) + a + result.slice(start + 1, end) + b + result.slice(end)
|
|
167
194
|
},
|
|
168
195
|
{ values: Object.fromEntries(pseudoVariants) }
|
|
169
196
|
)
|
|
@@ -1836,6 +1863,7 @@ export let corePlugins = {
|
|
|
1836
1863
|
{
|
|
1837
1864
|
text: (value) => {
|
|
1838
1865
|
let [fontSize, options] = Array.isArray(value) ? value : [value]
|
|
1866
|
+
|
|
1839
1867
|
let { lineHeight, letterSpacing, fontWeight } = isPlainObject(options)
|
|
1840
1868
|
? options
|
|
1841
1869
|
: { lineHeight: options }
|
package/src/index.js
CHANGED
|
@@ -1,47 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
module.exports = function tailwindcss(configOrPath) {
|
|
7
|
-
return {
|
|
8
|
-
postcssPlugin: 'tailwindcss',
|
|
9
|
-
plugins: [
|
|
10
|
-
env.DEBUG &&
|
|
11
|
-
function (root) {
|
|
12
|
-
console.log('\n')
|
|
13
|
-
console.time('JIT TOTAL')
|
|
14
|
-
return root
|
|
15
|
-
},
|
|
16
|
-
function (root, result) {
|
|
17
|
-
// Use the path for the `@config` directive if it exists, otherwise use the
|
|
18
|
-
// path for the file being processed
|
|
19
|
-
configOrPath = findAtConfigPath(root, result) ?? configOrPath
|
|
20
|
-
|
|
21
|
-
let context = setupTrackingContext(configOrPath)
|
|
22
|
-
|
|
23
|
-
if (root.type === 'document') {
|
|
24
|
-
let roots = root.nodes.filter((node) => node.type === 'root')
|
|
25
|
-
|
|
26
|
-
for (const root of roots) {
|
|
27
|
-
if (root.type === 'root') {
|
|
28
|
-
processTailwindFeatures(context)(root, result)
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
processTailwindFeatures(context)(root, result)
|
|
36
|
-
},
|
|
37
|
-
env.DEBUG &&
|
|
38
|
-
function (root) {
|
|
39
|
-
console.timeEnd('JIT TOTAL')
|
|
40
|
-
console.log('\n')
|
|
41
|
-
return root
|
|
42
|
-
},
|
|
43
|
-
].filter(Boolean),
|
|
44
|
-
}
|
|
1
|
+
if (process.env.OXIDE) {
|
|
2
|
+
module.exports = require('./oxide/postcss-plugin')
|
|
3
|
+
} else {
|
|
4
|
+
module.exports = require('./plugin')
|
|
45
5
|
}
|
|
46
|
-
|
|
47
|
-
module.exports.postcss = true
|
package/src/lib/content.js
CHANGED
|
@@ -164,50 +164,45 @@ function resolvePathSymlinks(contentPath) {
|
|
|
164
164
|
* @param {any} context
|
|
165
165
|
* @param {ContentPath[]} candidateFiles
|
|
166
166
|
* @param {Map<string, number>} fileModifiedMap
|
|
167
|
-
* @returns {{ content: string, extension: string }[]}
|
|
167
|
+
* @returns {[{ content: string, extension: string }[], Map<string, number>]}
|
|
168
168
|
*/
|
|
169
169
|
export function resolvedChangedContent(context, candidateFiles, fileModifiedMap) {
|
|
170
170
|
let changedContent = context.tailwindConfig.content.files
|
|
171
171
|
.filter((item) => typeof item.raw === 'string')
|
|
172
172
|
.map(({ raw, extension = 'html' }) => ({ content: raw, extension }))
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
let [changedFiles, mTimesToCommit] = resolveChangedFiles(candidateFiles, fileModifiedMap)
|
|
175
|
+
|
|
176
|
+
for (let changedFile of changedFiles) {
|
|
176
177
|
let extension = path.extname(changedFile).slice(1)
|
|
177
|
-
changedContent.push({
|
|
178
|
+
changedContent.push({ file: changedFile, extension })
|
|
178
179
|
}
|
|
179
180
|
|
|
180
|
-
return changedContent
|
|
181
|
+
return [changedContent, mTimesToCommit]
|
|
181
182
|
}
|
|
182
183
|
|
|
183
184
|
/**
|
|
184
185
|
*
|
|
185
186
|
* @param {ContentPath[]} candidateFiles
|
|
186
187
|
* @param {Map<string, number>} fileModifiedMap
|
|
187
|
-
* @returns {Set<string>}
|
|
188
|
+
* @returns {[Set<string>, Map<string, number>]}
|
|
188
189
|
*/
|
|
189
190
|
function resolveChangedFiles(candidateFiles, fileModifiedMap) {
|
|
190
191
|
let paths = candidateFiles.map((contentPath) => contentPath.pattern)
|
|
192
|
+
let mTimesToCommit = new Map()
|
|
191
193
|
|
|
192
194
|
let changedFiles = new Set()
|
|
193
195
|
env.DEBUG && console.time('Finding changed files')
|
|
194
196
|
let files = fastGlob.sync(paths, { absolute: true })
|
|
195
197
|
for (let file of files) {
|
|
196
|
-
let prevModified = fileModifiedMap.
|
|
198
|
+
let prevModified = fileModifiedMap.get(file) || -Infinity
|
|
197
199
|
let modified = fs.statSync(file).mtimeMs
|
|
198
200
|
|
|
199
|
-
|
|
200
|
-
// earier in the process and we want to make sure we don't miss any changes that happen
|
|
201
|
-
// when a context dependency is also a content dependency
|
|
202
|
-
// Ideally, we'd do all this tracking at one time but that is a larger refactor
|
|
203
|
-
// than we want to commit to right now, so this is a decent compromise.
|
|
204
|
-
// This should be sufficient because file modification times will be off by at least
|
|
205
|
-
// 1ms (the precision of fstat in Node) in most cases if they exist and were changed.
|
|
206
|
-
if (modified >= prevModified) {
|
|
201
|
+
if (modified > prevModified) {
|
|
207
202
|
changedFiles.add(file)
|
|
208
|
-
|
|
203
|
+
mTimesToCommit.set(file, modified)
|
|
209
204
|
}
|
|
210
205
|
}
|
|
211
206
|
env.DEBUG && console.timeEnd('Finding changed files')
|
|
212
|
-
return changedFiles
|
|
207
|
+
return [changedFiles, mTimesToCommit]
|
|
213
208
|
}
|
|
@@ -28,8 +28,14 @@ function* buildRegExps(context) {
|
|
|
28
28
|
: ''
|
|
29
29
|
|
|
30
30
|
let utility = regex.any([
|
|
31
|
-
// Arbitrary properties
|
|
32
|
-
/\[[^\s:'"`]+:[^\s]+\]/,
|
|
31
|
+
// Arbitrary properties (without square brackets)
|
|
32
|
+
/\[[^\s:'"`]+:[^\s\[\]]+\]/,
|
|
33
|
+
|
|
34
|
+
// Arbitrary properties with balanced square brackets
|
|
35
|
+
// This is a targeted fix to continue to allow theme()
|
|
36
|
+
// with square brackets to work in arbitrary properties
|
|
37
|
+
// while fixing a problem with the regex matching too much
|
|
38
|
+
/\[[^\s:'"`]+:[^\s]+?\[[^\s]+?\][^\s]+?\]/,
|
|
33
39
|
|
|
34
40
|
// Utilities
|
|
35
41
|
regex.pattern([
|
|
@@ -184,7 +190,7 @@ function clipAtBalancedParens(input) {
|
|
|
184
190
|
// This means that there was an extra closing `]`
|
|
185
191
|
// We'll clip to just before it
|
|
186
192
|
if (depth < 0) {
|
|
187
|
-
return input.substring(0, match.index)
|
|
193
|
+
return input.substring(0, match.index - 1)
|
|
188
194
|
}
|
|
189
195
|
|
|
190
196
|
// We've finished balancing the brackets but there still may be characters that can be included
|
package/src/lib/detectNesting.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
function isRoot(node) {
|
|
2
|
+
return node.type === 'root'
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function isAtLayer(node) {
|
|
6
|
+
return node.type === 'atrule' && node.name === 'layer'
|
|
7
|
+
}
|
|
8
|
+
|
|
1
9
|
export default function (_context) {
|
|
2
10
|
return (root, result) => {
|
|
3
11
|
let found = false
|
|
@@ -5,7 +13,7 @@ export default function (_context) {
|
|
|
5
13
|
root.walkAtRules('tailwind', (node) => {
|
|
6
14
|
if (found) return false
|
|
7
15
|
|
|
8
|
-
if (node.parent && node.parent
|
|
16
|
+
if (node.parent && !(isRoot(node.parent) || isAtLayer(node.parent))) {
|
|
9
17
|
found = true
|
|
10
18
|
node.warn(
|
|
11
19
|
result,
|