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.
Files changed (103) hide show
  1. package/CHANGELOG.md +56 -1
  2. package/README.md +1 -1
  3. package/lib/cli/build/index.js +5 -1
  4. package/lib/cli/build/plugin.js +50 -34
  5. package/lib/cli/build/watching.js +6 -3
  6. package/lib/cli/index.js +231 -10
  7. package/lib/cli/init/index.js +2 -2
  8. package/lib/cli.js +4 -226
  9. package/lib/corePlugins.js +45 -27
  10. package/lib/featureFlags.js +8 -8
  11. package/lib/index.js +4 -46
  12. package/lib/lib/collapseAdjacentRules.js +2 -2
  13. package/lib/lib/collapseDuplicateDeclarations.js +2 -2
  14. package/lib/lib/content.js +16 -16
  15. package/lib/lib/defaultExtractor.js +10 -5
  16. package/lib/lib/detectNesting.js +7 -1
  17. package/lib/lib/evaluateTailwindFunctions.js +4 -4
  18. package/lib/lib/expandApplyAtRules.js +2 -2
  19. package/lib/lib/expandTailwindAtRules.js +35 -9
  20. package/lib/lib/findAtConfigPath.js +3 -3
  21. package/lib/lib/generateRules.js +105 -50
  22. package/lib/lib/offsets.js +88 -1
  23. package/lib/lib/remap-bitfield.js +87 -0
  24. package/lib/lib/resolveDefaultsAtRules.js +4 -4
  25. package/lib/lib/setupContextUtils.js +122 -79
  26. package/lib/lib/setupTrackingContext.js +25 -4
  27. package/lib/lib/sharedState.js +19 -1
  28. package/lib/oxide/cli/build/deps.js +81 -0
  29. package/lib/oxide/cli/build/index.js +47 -0
  30. package/lib/oxide/cli/build/plugin.js +364 -0
  31. package/lib/oxide/cli/build/utils.js +77 -0
  32. package/lib/oxide/cli/build/watching.js +177 -0
  33. package/lib/oxide/cli/help/index.js +70 -0
  34. package/lib/oxide/cli/index.js +220 -0
  35. package/lib/oxide/cli/init/index.js +35 -0
  36. package/lib/oxide/cli.js +5 -0
  37. package/lib/oxide/postcss-plugin.js +2 -0
  38. package/lib/plugin.js +98 -0
  39. package/lib/postcss-plugins/nesting/plugin.js +2 -2
  40. package/lib/util/cloneNodes.js +2 -2
  41. package/lib/util/color.js +20 -6
  42. package/lib/util/createUtilityPlugin.js +2 -2
  43. package/lib/util/dataTypes.js +26 -2
  44. package/lib/util/defaults.js +4 -4
  45. package/lib/util/escapeClassName.js +3 -3
  46. package/lib/util/formatVariantSelector.js +171 -105
  47. package/lib/util/getAllConfigs.js +2 -2
  48. package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +2 -2
  49. package/lib/util/negateValue.js +2 -2
  50. package/lib/util/normalizeConfig.js +36 -22
  51. package/lib/util/pluginUtils.js +38 -40
  52. package/lib/util/prefixSelector.js +22 -8
  53. package/lib/util/resolveConfig.js +8 -10
  54. package/oxide-node-api-shim/index.js +21 -0
  55. package/oxide-node-api-shim/package.json +5 -0
  56. package/package.json +32 -19
  57. package/peers/index.js +61 -42
  58. package/resolveConfig.d.ts +11 -2
  59. package/scripts/swap-engines.js +40 -0
  60. package/src/cli/build/index.js +6 -2
  61. package/src/cli/build/plugin.js +31 -9
  62. package/src/cli/build/watching.js +6 -3
  63. package/src/cli/index.js +234 -3
  64. package/src/cli.js +4 -220
  65. package/src/corePlugins.js +31 -3
  66. package/src/index.js +4 -46
  67. package/src/lib/content.js +12 -17
  68. package/src/lib/defaultExtractor.js +9 -3
  69. package/src/lib/detectNesting.js +9 -1
  70. package/src/lib/expandTailwindAtRules.js +37 -6
  71. package/src/lib/generateRules.js +90 -28
  72. package/src/lib/offsets.js +104 -1
  73. package/src/lib/remap-bitfield.js +82 -0
  74. package/src/lib/setupContextUtils.js +99 -56
  75. package/src/lib/setupTrackingContext.js +31 -6
  76. package/src/lib/sharedState.js +17 -0
  77. package/src/oxide/cli/build/deps.ts +91 -0
  78. package/src/oxide/cli/build/index.ts +47 -0
  79. package/src/oxide/cli/build/plugin.ts +436 -0
  80. package/src/oxide/cli/build/utils.ts +74 -0
  81. package/src/oxide/cli/build/watching.ts +225 -0
  82. package/src/oxide/cli/help/index.ts +69 -0
  83. package/src/oxide/cli/index.ts +212 -0
  84. package/src/oxide/cli/init/index.ts +32 -0
  85. package/src/oxide/cli.ts +1 -0
  86. package/src/oxide/postcss-plugin.ts +1 -0
  87. package/src/plugin.js +107 -0
  88. package/src/util/color.js +17 -2
  89. package/src/util/dataTypes.js +29 -4
  90. package/src/util/formatVariantSelector.js +215 -122
  91. package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
  92. package/src/util/negateValue.js +1 -1
  93. package/src/util/normalizeConfig.js +18 -0
  94. package/src/util/pluginUtils.js +22 -19
  95. package/src/util/prefixSelector.js +28 -10
  96. package/src/util/resolveConfig.js +0 -2
  97. package/stubs/defaultConfig.stub.js +149 -165
  98. package/types/config.d.ts +7 -2
  99. package/types/generated/default-theme.d.ts +77 -77
  100. package/lib/cli/shared.js +0 -12
  101. package/scripts/install-integrations.js +0 -27
  102. package/scripts/rebuildFixtures.js +0 -68
  103. package/src/cli/shared.js +0 -5
@@ -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 '../shared'
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
- content.push({
188
- content: fs.readFileSync(path.resolve(file), 'utf8'),
189
- extension: path.extname(file).slice(1),
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(output, result.css),
359
- result.map && outputFile(output + '.map', result.map.toString()),
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
- export * from './build'
2
- export * from './config'
3
- export * from './content'
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
- import path from 'path'
4
- import arg from 'arg'
5
- import fs from 'fs'
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)
@@ -150,9 +150,13 @@ export let variantPlugins = {
150
150
 
151
151
  let variants = {
152
152
  group: (_, { modifier }) =>
153
- modifier ? [`:merge(.group\\/${modifier})`, ' &'] : [`:merge(.group)`, ' &'],
153
+ modifier
154
+ ? [`:merge(.group\\/${escapeClassName(modifier)})`, ' &']
155
+ : [`:merge(.group)`, ' &'],
154
156
  peer: (_, { modifier }) =>
155
- modifier ? [`:merge(.peer\\/${modifier})`, ' ~ &'] : [`:merge(.peer)`, ' ~ &'],
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
- return result.replace(/&(\S+)?/g, (_, pseudo = '') => a + pseudo + b)
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
- import setupTrackingContext from './lib/setupTrackingContext'
2
- import processTailwindFeatures from './processTailwindFeatures'
3
- import { env } from './lib/sharedState'
4
- import { findAtConfigPath } from './lib/findAtConfigPath'
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