tailwindcss 3.2.3 → 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 +56 -1
- package/README.md +1 -1
- package/lib/cli/build/index.js +5 -1
- package/lib/cli/build/plugin.js +50 -34
- package/lib/cli/build/watching.js +6 -3
- 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 +122 -79
- 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 +36 -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 +31 -9
- package/src/cli/build/watching.js +6 -3
- 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 +99 -56
- 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/normalizeConfig.js +18 -0
- 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/build/plugin.js
CHANGED
|
@@ -10,7 +10,7 @@ import loadOptions from 'postcss-load-config/src/options' // Little bit scary, l
|
|
|
10
10
|
import tailwind from '../../processTailwindFeatures'
|
|
11
11
|
import { loadAutoprefixer, loadCssNano, loadPostcss, loadPostcssImport } from './deps'
|
|
12
12
|
import { formatNodes, drainStdin, outputFile } from './utils'
|
|
13
|
-
import { env } from '
|
|
13
|
+
import { env } from '../../lib/sharedState'
|
|
14
14
|
import resolveConfig from '../../../resolveConfig.js'
|
|
15
15
|
import getModuleDependencies from '../../lib/getModuleDependencies.js'
|
|
16
16
|
import { parseCandidateFiles } from '../../lib/content.js'
|
|
@@ -184,10 +184,17 @@ let state = {
|
|
|
184
184
|
let files = fastGlob.sync(this.contentPatterns.all)
|
|
185
185
|
|
|
186
186
|
for (let file of files) {
|
|
187
|
-
|
|
188
|
-
content
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
if (env.OXIDE) {
|
|
188
|
+
content.push({
|
|
189
|
+
file,
|
|
190
|
+
extension: path.extname(file).slice(1),
|
|
191
|
+
})
|
|
192
|
+
} else {
|
|
193
|
+
content.push({
|
|
194
|
+
content: fs.readFileSync(path.resolve(file), 'utf8'),
|
|
195
|
+
extension: path.extname(file).slice(1),
|
|
196
|
+
})
|
|
197
|
+
}
|
|
191
198
|
}
|
|
192
199
|
|
|
193
200
|
// Resolve raw content in the tailwind config
|
|
@@ -234,11 +241,9 @@ let state = {
|
|
|
234
241
|
env.DEBUG && console.timeEnd('Watch new files')
|
|
235
242
|
}
|
|
236
243
|
|
|
237
|
-
env.DEBUG && console.time('Reading content files')
|
|
238
244
|
for (let file of this.readContentPaths()) {
|
|
239
245
|
this.context.changedContent.push(file)
|
|
240
246
|
}
|
|
241
|
-
env.DEBUG && console.timeEnd('Reading content files')
|
|
242
247
|
|
|
243
248
|
return this.context
|
|
244
249
|
},
|
|
@@ -355,8 +360,8 @@ export async function createProcessor(args, cliConfigPath) {
|
|
|
355
360
|
}
|
|
356
361
|
|
|
357
362
|
return Promise.all([
|
|
358
|
-
outputFile(
|
|
359
|
-
result.map && outputFile(
|
|
363
|
+
outputFile(result.opts.to, result.css),
|
|
364
|
+
result.map && outputFile(result.opts.to + '.map', result.map.toString()),
|
|
360
365
|
])
|
|
361
366
|
})
|
|
362
367
|
.then(() => {
|
|
@@ -364,6 +369,23 @@ export async function createProcessor(args, cliConfigPath) {
|
|
|
364
369
|
console.error()
|
|
365
370
|
console.error('Done in', (end - start) / BigInt(1e6) + 'ms.')
|
|
366
371
|
})
|
|
372
|
+
.then(
|
|
373
|
+
() => {},
|
|
374
|
+
(err) => {
|
|
375
|
+
// TODO: If an initial build fails we can't easily pick up any PostCSS dependencies
|
|
376
|
+
// that were collected before the error occurred
|
|
377
|
+
// The result is not stored on the error so we have to store it externally
|
|
378
|
+
// and pull the messages off of it here somehow
|
|
379
|
+
|
|
380
|
+
// This results in a less than ideal DX because the watcher will not pick up
|
|
381
|
+
// changes to imported CSS if one of them caused an error during the initial build
|
|
382
|
+
// If you fix it and then save the main CSS file so there's no error
|
|
383
|
+
// The watcher will start watching the imported CSS files and will be
|
|
384
|
+
// resilient to future errors.
|
|
385
|
+
|
|
386
|
+
console.error(err)
|
|
387
|
+
}
|
|
388
|
+
)
|
|
367
389
|
}
|
|
368
390
|
|
|
369
391
|
/**
|
|
@@ -97,14 +97,15 @@ export function createWatcher(args, { state, rebuild }) {
|
|
|
97
97
|
*
|
|
98
98
|
* @param {*} file
|
|
99
99
|
* @param {(() => Promise<string>) | null} content
|
|
100
|
+
* @param {boolean} skipPendingCheck
|
|
100
101
|
* @returns {Promise<void>}
|
|
101
102
|
*/
|
|
102
|
-
function recordChangedFile(file, content = null) {
|
|
103
|
+
function recordChangedFile(file, content = null, skipPendingCheck = false) {
|
|
103
104
|
file = path.resolve(file)
|
|
104
105
|
|
|
105
106
|
// Applications like Vim/Neovim fire both rename and change events in succession for atomic writes
|
|
106
107
|
// In that case rebuild has already been queued by rename, so can be skipped in change
|
|
107
|
-
if (pendingRebuilds.has(file)) {
|
|
108
|
+
if (pendingRebuilds.has(file) && !skipPendingCheck) {
|
|
108
109
|
return Promise.resolve()
|
|
109
110
|
}
|
|
110
111
|
|
|
@@ -198,8 +199,10 @@ export function createWatcher(args, { state, rebuild }) {
|
|
|
198
199
|
}
|
|
199
200
|
|
|
200
201
|
// This will push the rebuild onto the chain
|
|
202
|
+
// We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux
|
|
203
|
+
// This is because the order of events and timing is different on Linux
|
|
201
204
|
// @ts-ignore: TypeScript isn't picking up that content is a string here
|
|
202
|
-
await recordChangedFile(filePath, () => content)
|
|
205
|
+
await recordChangedFile(filePath, () => content, true)
|
|
203
206
|
} catch {
|
|
204
207
|
// If reading the file fails, it's was probably a deleted temporary file
|
|
205
208
|
// So we can ignore it and no rebuild is needed
|
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
|