tailwindcss 0.0.0-insiders.bd4dddd → 0.0.0-insiders.bda8421

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 (224) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +13 -10
  3. package/colors.d.ts +3 -0
  4. package/defaultConfig.d.ts +3 -0
  5. package/defaultTheme.d.ts +4 -0
  6. package/lib/cli/build/deps.js +62 -0
  7. package/lib/cli/build/index.js +54 -0
  8. package/lib/cli/build/plugin.js +371 -0
  9. package/lib/cli/build/utils.js +88 -0
  10. package/lib/cli/build/watching.js +182 -0
  11. package/lib/cli/help/index.js +73 -0
  12. package/lib/cli/index.js +230 -0
  13. package/lib/cli/init/index.js +63 -0
  14. package/lib/cli-peer-dependencies.js +28 -7
  15. package/lib/cli.js +1 -741
  16. package/lib/corePluginList.js +17 -4
  17. package/lib/corePlugins.js +2503 -1839
  18. package/lib/css/preflight.css +32 -13
  19. package/lib/featureFlags.js +45 -28
  20. package/lib/index.js +1 -29
  21. package/lib/lib/cacheInvalidation.js +92 -0
  22. package/lib/lib/collapseAdjacentRules.js +30 -10
  23. package/lib/lib/collapseDuplicateDeclarations.js +13 -8
  24. package/lib/lib/content.js +214 -0
  25. package/lib/lib/defaultExtractor.js +240 -31
  26. package/lib/lib/evaluateTailwindFunctions.js +117 -50
  27. package/lib/lib/expandApplyAtRules.js +466 -230
  28. package/lib/lib/expandTailwindAtRules.js +156 -135
  29. package/lib/lib/findAtConfigPath.js +46 -0
  30. package/lib/lib/generateRules.js +554 -200
  31. package/lib/lib/getModuleDependencies.js +88 -37
  32. package/lib/lib/load-config.js +57 -0
  33. package/lib/lib/normalizeTailwindDirectives.js +39 -33
  34. package/lib/lib/offsets.js +355 -0
  35. package/lib/lib/partitionApplyAtRules.js +58 -0
  36. package/lib/lib/regex.js +74 -0
  37. package/lib/lib/remap-bitfield.js +89 -0
  38. package/lib/lib/resolveDefaultsAtRules.js +97 -69
  39. package/lib/lib/setupContextUtils.js +796 -341
  40. package/lib/lib/setupTrackingContext.js +66 -71
  41. package/lib/lib/sharedState.js +45 -14
  42. package/lib/lib/substituteScreenAtRules.js +14 -10
  43. package/lib/plugin.js +48 -0
  44. package/{nesting → lib/postcss-plugins/nesting}/README.md +2 -2
  45. package/lib/postcss-plugins/nesting/index.js +21 -0
  46. package/lib/postcss-plugins/nesting/plugin.js +89 -0
  47. package/lib/processTailwindFeatures.js +37 -27
  48. package/lib/public/colors.js +272 -246
  49. package/lib/public/create-plugin.js +9 -5
  50. package/lib/public/default-config.js +10 -6
  51. package/lib/public/default-theme.js +10 -6
  52. package/lib/public/load-config.js +12 -0
  53. package/lib/public/resolve-config.js +11 -6
  54. package/lib/util/applyImportantSelector.js +36 -0
  55. package/lib/util/bigSign.js +6 -1
  56. package/lib/util/buildMediaQuery.js +13 -6
  57. package/lib/util/cloneDeep.js +9 -6
  58. package/lib/util/cloneNodes.js +44 -4
  59. package/lib/util/color.js +70 -53
  60. package/lib/util/colorNames.js +752 -0
  61. package/lib/util/configurePlugins.js +7 -2
  62. package/lib/util/createPlugin.js +8 -6
  63. package/lib/util/createUtilityPlugin.js +16 -16
  64. package/lib/util/dataTypes.js +295 -113
  65. package/lib/util/defaults.js +12 -7
  66. package/lib/util/escapeClassName.js +13 -8
  67. package/lib/util/escapeCommas.js +7 -2
  68. package/lib/util/flattenColorPalette.js +11 -12
  69. package/lib/util/formatVariantSelector.js +235 -151
  70. package/lib/util/getAllConfigs.js +33 -12
  71. package/lib/util/hashConfig.js +9 -4
  72. package/lib/util/isKeyframeRule.js +7 -2
  73. package/lib/util/isPlainObject.js +8 -3
  74. package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +25 -15
  75. package/lib/util/log.js +25 -15
  76. package/lib/util/nameClass.js +27 -10
  77. package/lib/util/negateValue.js +25 -8
  78. package/lib/util/normalizeConfig.js +127 -82
  79. package/lib/util/normalizeScreens.js +128 -11
  80. package/lib/util/parseAnimationValue.js +44 -40
  81. package/lib/util/parseBoxShadowValue.js +34 -23
  82. package/lib/util/parseDependency.js +39 -55
  83. package/lib/util/parseGlob.js +36 -0
  84. package/lib/util/parseObjectStyles.js +15 -10
  85. package/lib/util/pluginUtils.js +172 -69
  86. package/lib/util/prefixSelector.js +30 -12
  87. package/lib/util/pseudoElements.js +212 -0
  88. package/lib/util/removeAlphaVariables.js +31 -0
  89. package/lib/util/resolveConfig.js +101 -87
  90. package/lib/util/resolveConfigPath.js +30 -12
  91. package/lib/util/responsive.js +11 -6
  92. package/lib/util/splitAtTopLevelOnly.js +51 -0
  93. package/lib/util/tap.js +6 -1
  94. package/lib/util/toColorValue.js +7 -3
  95. package/lib/util/toPath.js +22 -4
  96. package/lib/util/transformThemeValue.js +40 -30
  97. package/lib/util/validateConfig.js +37 -0
  98. package/lib/util/validateFormalSyntax.js +26 -0
  99. package/lib/util/withAlphaVariable.js +27 -15
  100. package/lib/value-parser/LICENSE +22 -0
  101. package/lib/value-parser/README.md +3 -0
  102. package/lib/value-parser/index.d.js +2 -0
  103. package/lib/value-parser/index.js +22 -0
  104. package/lib/value-parser/parse.js +259 -0
  105. package/lib/value-parser/stringify.js +38 -0
  106. package/lib/value-parser/unit.js +86 -0
  107. package/lib/value-parser/walk.js +16 -0
  108. package/loadConfig.d.ts +4 -0
  109. package/loadConfig.js +2 -0
  110. package/nesting/index.d.ts +4 -0
  111. package/nesting/index.js +2 -12
  112. package/package.json +60 -55
  113. package/peers/index.js +75503 -55095
  114. package/plugin.d.ts +11 -0
  115. package/resolveConfig.d.ts +31 -0
  116. package/scripts/generate-types.js +104 -0
  117. package/scripts/release-channel.js +18 -0
  118. package/scripts/release-notes.js +21 -0
  119. package/scripts/type-utils.js +27 -0
  120. package/src/cli/build/deps.js +56 -0
  121. package/src/cli/build/index.js +49 -0
  122. package/src/cli/build/plugin.js +437 -0
  123. package/src/cli/build/utils.js +76 -0
  124. package/src/cli/build/watching.js +229 -0
  125. package/src/cli/help/index.js +70 -0
  126. package/src/cli/index.js +216 -0
  127. package/src/cli/init/index.js +79 -0
  128. package/src/cli-peer-dependencies.js +7 -1
  129. package/src/cli.js +1 -811
  130. package/src/corePluginList.js +1 -1
  131. package/src/corePlugins.js +849 -243
  132. package/src/css/preflight.css +32 -13
  133. package/src/featureFlags.js +13 -9
  134. package/src/index.js +1 -28
  135. package/src/lib/cacheInvalidation.js +52 -0
  136. package/src/lib/collapseAdjacentRules.js +21 -2
  137. package/src/lib/content.js +249 -0
  138. package/src/lib/defaultExtractor.js +215 -33
  139. package/src/lib/evaluateTailwindFunctions.js +82 -8
  140. package/src/lib/expandApplyAtRules.js +512 -224
  141. package/src/lib/expandTailwindAtRules.js +102 -87
  142. package/src/lib/findAtConfigPath.js +48 -0
  143. package/src/lib/generateRules.js +541 -146
  144. package/src/lib/getModuleDependencies.js +70 -30
  145. package/src/lib/load-config.ts +44 -0
  146. package/src/lib/normalizeTailwindDirectives.js +1 -0
  147. package/src/lib/offsets.js +432 -0
  148. package/src/lib/partitionApplyAtRules.js +52 -0
  149. package/src/lib/regex.js +74 -0
  150. package/src/lib/remap-bitfield.js +82 -0
  151. package/src/lib/resolveDefaultsAtRules.js +55 -30
  152. package/src/lib/setupContextUtils.js +720 -190
  153. package/src/lib/setupTrackingContext.js +47 -61
  154. package/src/lib/sharedState.js +15 -4
  155. package/src/plugin.js +47 -0
  156. package/src/postcss-plugins/nesting/README.md +42 -0
  157. package/src/postcss-plugins/nesting/index.js +13 -0
  158. package/src/postcss-plugins/nesting/plugin.js +80 -0
  159. package/src/processTailwindFeatures.js +11 -4
  160. package/src/public/colors.js +22 -0
  161. package/src/public/default-config.js +1 -1
  162. package/src/public/default-theme.js +2 -2
  163. package/src/public/load-config.js +2 -0
  164. package/src/util/applyImportantSelector.js +27 -0
  165. package/src/util/buildMediaQuery.js +5 -3
  166. package/src/util/cloneNodes.js +40 -2
  167. package/src/util/color.js +39 -20
  168. package/src/util/colorNames.js +150 -0
  169. package/src/util/dataTypes.js +184 -26
  170. package/src/util/formatVariantSelector.js +272 -144
  171. package/src/util/getAllConfigs.js +21 -2
  172. package/src/util/isPlainObject.js +1 -1
  173. package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
  174. package/src/util/log.js +8 -8
  175. package/src/util/nameClass.js +4 -0
  176. package/src/util/negateValue.js +11 -3
  177. package/src/util/normalizeConfig.js +45 -6
  178. package/src/util/normalizeScreens.js +99 -4
  179. package/src/util/parseBoxShadowValue.js +4 -3
  180. package/src/util/parseDependency.js +37 -42
  181. package/src/util/parseGlob.js +24 -0
  182. package/src/util/pluginUtils.js +139 -24
  183. package/src/util/prefixSelector.js +31 -10
  184. package/src/util/pseudoElements.js +171 -0
  185. package/src/util/removeAlphaVariables.js +24 -0
  186. package/src/util/resolveConfig.js +70 -32
  187. package/src/util/resolveConfigPath.js +12 -1
  188. package/src/util/splitAtTopLevelOnly.js +52 -0
  189. package/src/util/toPath.js +1 -1
  190. package/src/util/transformThemeValue.js +13 -3
  191. package/src/util/validateConfig.js +26 -0
  192. package/src/util/validateFormalSyntax.js +34 -0
  193. package/src/util/withAlphaVariable.js +1 -1
  194. package/src/value-parser/LICENSE +22 -0
  195. package/src/value-parser/README.md +3 -0
  196. package/src/value-parser/index.d.ts +177 -0
  197. package/src/value-parser/index.js +28 -0
  198. package/src/value-parser/parse.js +303 -0
  199. package/src/value-parser/stringify.js +41 -0
  200. package/src/value-parser/unit.js +118 -0
  201. package/src/value-parser/walk.js +18 -0
  202. package/stubs/.gitignore +1 -0
  203. package/stubs/.prettierrc.json +6 -0
  204. package/stubs/{defaultConfig.stub.js → config.full.js} +290 -178
  205. package/stubs/postcss.config.js +6 -0
  206. package/stubs/tailwind.config.cjs +2 -0
  207. package/stubs/tailwind.config.js +2 -0
  208. package/stubs/tailwind.config.ts +3 -0
  209. package/types/config.d.ts +376 -0
  210. package/types/generated/.gitkeep +0 -0
  211. package/types/generated/colors.d.ts +298 -0
  212. package/types/generated/corePluginList.d.ts +1 -0
  213. package/types/generated/default-theme.d.ts +397 -0
  214. package/types/index.d.ts +11 -0
  215. package/CHANGELOG.md +0 -1959
  216. package/lib/constants.js +0 -37
  217. package/lib/lib/detectNesting.js +0 -34
  218. package/nesting/plugin.js +0 -41
  219. package/scripts/install-integrations.js +0 -27
  220. package/scripts/rebuildFixtures.js +0 -68
  221. package/src/constants.js +0 -17
  222. package/src/lib/detectNesting.js +0 -39
  223. /package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -0
  224. /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
@@ -1,3 +1,4 @@
1
+ import { flagEnabled } from '../featureFlags'
1
2
  import log, { dim } from './log'
2
3
 
3
4
  export function normalizeConfig(config) {
@@ -56,9 +57,11 @@ export function normalizeConfig(config) {
56
57
 
57
58
  // When `config.content` is an object
58
59
  if (typeof config.content === 'object' && config.content !== null) {
59
- // Only `files`, `extract` and `transform` can exist in `config.content`
60
+ // Only `files`, `relative`, `extract`, and `transform` can exist in `config.content`
60
61
  if (
61
- Object.keys(config.content).some((key) => !['files', 'extract', 'transform'].includes(key))
62
+ Object.keys(config.content).some(
63
+ (key) => !['files', 'relative', 'extract', 'transform'].includes(key)
64
+ )
62
65
  ) {
63
66
  return false
64
67
  }
@@ -112,6 +115,14 @@ export function normalizeConfig(config) {
112
115
  ) {
113
116
  return false
114
117
  }
118
+
119
+ // `config.content.relative` is optional and can be a boolean
120
+ if (
121
+ typeof config.content.relative !== 'boolean' &&
122
+ typeof config.content.relative !== 'undefined'
123
+ ) {
124
+ return false
125
+ }
115
126
  }
116
127
 
117
128
  return true
@@ -124,7 +135,7 @@ export function normalizeConfig(config) {
124
135
  log.warn('purge-deprecation', [
125
136
  'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
126
137
  'Update your configuration file to eliminate this warning.',
127
- // TODO: Add https://tw.wtf/purge-deprecation
138
+ 'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources',
128
139
  ])
129
140
  }
130
141
 
@@ -140,12 +151,30 @@ export function normalizeConfig(config) {
140
151
  return []
141
152
  })()
142
153
 
154
+ // Normalize the `blocklist`
155
+ config.blocklist = (() => {
156
+ let { blocklist } = config
157
+
158
+ if (Array.isArray(blocklist)) {
159
+ if (blocklist.every((item) => typeof item === 'string')) {
160
+ return blocklist
161
+ }
162
+
163
+ log.warn('blocklist-invalid', [
164
+ 'The `blocklist` option must be an array of strings.',
165
+ 'https://tailwindcss.com/docs/content-configuration#discarding-classes',
166
+ ])
167
+ }
168
+
169
+ return []
170
+ })()
171
+
143
172
  // Normalize prefix option
144
173
  if (typeof config.prefix === 'function') {
145
174
  log.warn('prefix-function', [
146
175
  'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
147
176
  'Update `prefix` in your configuration to be a string to eliminate this warning.',
148
- // TODO: Add https://tw.wtf/prefix-function
177
+ 'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function',
149
178
  ])
150
179
  config.prefix = ''
151
180
  } else {
@@ -154,6 +183,16 @@ export function normalizeConfig(config) {
154
183
 
155
184
  // Normalize the `content`
156
185
  config.content = {
186
+ relative: (() => {
187
+ let { content } = config
188
+
189
+ if (content?.relative) {
190
+ return content.relative
191
+ }
192
+
193
+ return flagEnabled(config, 'relativeContentPathsByDefault')
194
+ })(),
195
+
157
196
  files: (() => {
158
197
  let { content, purge } = config
159
198
 
@@ -250,8 +289,8 @@ export function normalizeConfig(config) {
250
289
  for (let file of config.content.files) {
251
290
  if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
252
291
  log.warn('invalid-glob-braces', [
253
- `The glob pattern ${dim(file)} in your config is invalid.`,
254
- ` Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
292
+ `The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`,
293
+ `Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
255
294
  // TODO: Add https://tw.wtf/invalid-glob-braces
256
295
  ])
257
296
  break
@@ -1,3 +1,17 @@
1
+ /**
2
+ * @typedef {object} ScreenValue
3
+ * @property {number|undefined} min
4
+ * @property {number|undefined} max
5
+ * @property {string|undefined} raw
6
+ */
7
+
8
+ /**
9
+ * @typedef {object} Screen
10
+ * @property {string} name
11
+ * @property {boolean} not
12
+ * @property {ScreenValue[]} values
13
+ */
14
+
1
15
  /**
2
16
  * A function that normalizes the various forms that the screens object can be
3
17
  * provided in.
@@ -10,6 +24,8 @@
10
24
  *
11
25
  * Output(s):
12
26
  * - [{ name: 'sm', values: [{ min: '100px', max: '200px' }] }] // List of objects, that contains multiple values
27
+ *
28
+ * @returns {Screen[]}
13
29
  */
14
30
  export function normalizeScreens(screens, root = true) {
15
31
  if (Array.isArray(screens)) {
@@ -19,27 +35,106 @@ export function normalizeScreens(screens, root = true) {
19
35
  }
20
36
 
21
37
  if (typeof screen === 'string') {
22
- return { name: screen.toString(), values: [{ min: screen, max: undefined }] }
38
+ return { name: screen.toString(), not: false, values: [{ min: screen, max: undefined }] }
23
39
  }
24
40
 
25
41
  let [name, options] = screen
26
42
  name = name.toString()
27
43
 
28
44
  if (typeof options === 'string') {
29
- return { name, values: [{ min: options, max: undefined }] }
45
+ return { name, not: false, values: [{ min: options, max: undefined }] }
30
46
  }
31
47
 
32
48
  if (Array.isArray(options)) {
33
- return { name, values: options.map((option) => resolveValue(option)) }
49
+ return { name, not: false, values: options.map((option) => resolveValue(option)) }
34
50
  }
35
51
 
36
- return { name, values: [resolveValue(options)] }
52
+ return { name, not: false, values: [resolveValue(options)] }
37
53
  })
38
54
  }
39
55
 
40
56
  return normalizeScreens(Object.entries(screens ?? {}), false)
41
57
  }
42
58
 
59
+ /**
60
+ * @param {Screen} screen
61
+ * @returns {{result: false, reason: string} | {result: true, reason: null}}
62
+ */
63
+ export function isScreenSortable(screen) {
64
+ if (screen.values.length !== 1) {
65
+ return { result: false, reason: 'multiple-values' }
66
+ } else if (screen.values[0].raw !== undefined) {
67
+ return { result: false, reason: 'raw-values' }
68
+ } else if (screen.values[0].min !== undefined && screen.values[0].max !== undefined) {
69
+ return { result: false, reason: 'min-and-max' }
70
+ }
71
+
72
+ return { result: true, reason: null }
73
+ }
74
+
75
+ /**
76
+ * @param {'min' | 'max'} type
77
+ * @param {Screen | 'string'} a
78
+ * @param {Screen | 'string'} z
79
+ * @returns {number}
80
+ */
81
+ export function compareScreens(type, a, z) {
82
+ let aScreen = toScreen(a, type)
83
+ let zScreen = toScreen(z, type)
84
+
85
+ let aSorting = isScreenSortable(aScreen)
86
+ let bSorting = isScreenSortable(zScreen)
87
+
88
+ // These cases should never happen and indicate a bug in Tailwind CSS itself
89
+ if (aSorting.reason === 'multiple-values' || bSorting.reason === 'multiple-values') {
90
+ throw new Error(
91
+ 'Attempted to sort a screen with multiple values. This should never happen. Please open a bug report.'
92
+ )
93
+ } else if (aSorting.reason === 'raw-values' || bSorting.reason === 'raw-values') {
94
+ throw new Error(
95
+ 'Attempted to sort a screen with raw values. This should never happen. Please open a bug report.'
96
+ )
97
+ } else if (aSorting.reason === 'min-and-max' || bSorting.reason === 'min-and-max') {
98
+ throw new Error(
99
+ 'Attempted to sort a screen with both min and max values. This should never happen. Please open a bug report.'
100
+ )
101
+ }
102
+
103
+ // Let the sorting begin
104
+ let { min: aMin, max: aMax } = aScreen.values[0]
105
+ let { min: zMin, max: zMax } = zScreen.values[0]
106
+
107
+ // Negating screens flip their behavior. Basically `not min-width` is `max-width`
108
+ if (a.not) [aMin, aMax] = [aMax, aMin]
109
+ if (z.not) [zMin, zMax] = [zMax, zMin]
110
+
111
+ aMin = aMin === undefined ? aMin : parseFloat(aMin)
112
+ aMax = aMax === undefined ? aMax : parseFloat(aMax)
113
+ zMin = zMin === undefined ? zMin : parseFloat(zMin)
114
+ zMax = zMax === undefined ? zMax : parseFloat(zMax)
115
+
116
+ let [aValue, zValue] = type === 'min' ? [aMin, zMin] : [zMax, aMax]
117
+
118
+ return aValue - zValue
119
+ }
120
+
121
+ /**
122
+ *
123
+ * @param {PartialScreen> | string} value
124
+ * @param {'min' | 'max'} type
125
+ * @returns {Screen}
126
+ */
127
+ export function toScreen(value, type) {
128
+ if (typeof value === 'object') {
129
+ return value
130
+ }
131
+
132
+ return {
133
+ name: 'arbitrary-screen',
134
+ values: [{ [type]: value }],
135
+ }
136
+ }
137
+
43
138
  function resolveValue({ 'min-width': _minWidth, min = _minWidth, max, raw } = {}) {
44
139
  return { min, max, raw }
45
140
  }
@@ -1,10 +1,11 @@
1
+ import { splitAtTopLevelOnly } from './splitAtTopLevelOnly'
2
+
1
3
  let KEYWORDS = new Set(['inset', 'inherit', 'initial', 'revert', 'unset'])
2
- let COMMA = /\,(?![^(]*\))/g // Comma separator that is not located between brackets. E.g.: `cubiz-bezier(a, b, c)` these don't count.
3
4
  let SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
4
- let LENGTH = /^-?(\d+)(.*?)$/g
5
+ let LENGTH = /^-?(\d+|\.\d+)(.*?)$/g
5
6
 
6
7
  export function parseBoxShadowValue(input) {
7
- let shadows = input.split(COMMA)
8
+ let shadows = splitAtTopLevelOnly(input, ',')
8
9
  return shadows.map((shadow) => {
9
10
  let value = shadow.trim()
10
11
  let result = { raw: value }
@@ -1,49 +1,44 @@
1
- import isGlob from 'is-glob'
2
- import globParent from 'glob-parent'
3
- import path from 'path'
4
-
5
- // Based on `glob-base`
6
- // https://github.com/micromatch/glob-base/blob/master/index.js
7
- function parseGlob(pattern) {
8
- let glob = pattern
9
- let base = globParent(pattern)
10
-
11
- if (base !== '.') {
12
- glob = pattern.substr(base.length)
13
- if (glob.charAt(0) === '/') {
14
- glob = glob.substr(1)
15
- }
16
- }
17
-
18
- if (glob.substr(0, 2) === './') {
19
- glob = glob.substr(2)
20
- }
21
- if (glob.charAt(0) === '/') {
22
- glob = glob.substr(1)
1
+ // @ts-check
2
+
3
+ /**
4
+ * @typedef {{type: 'dependency', file: string} | {type: 'dir-dependency', dir: string, glob: string}} Dependency
5
+ */
6
+
7
+ /**
8
+ *
9
+ * @param {import('../lib/content.js').ContentPath} contentPath
10
+ * @returns {Dependency[]}
11
+ */
12
+ export default function parseDependency(contentPath) {
13
+ if (contentPath.ignore) {
14
+ return []
23
15
  }
24
16
 
25
- return { base, glob }
26
- }
27
-
28
- export default function parseDependency(normalizedFileOrGlob) {
29
- if (normalizedFileOrGlob.startsWith('!')) {
30
- return null
31
- }
32
-
33
- let message
34
-
35
- if (isGlob(normalizedFileOrGlob)) {
36
- let { base, glob } = parseGlob(normalizedFileOrGlob)
37
- message = { type: 'dir-dependency', dir: path.resolve(base), glob }
38
- } else {
39
- message = { type: 'dependency', file: path.resolve(normalizedFileOrGlob) }
17
+ if (!contentPath.glob) {
18
+ return [
19
+ {
20
+ type: 'dependency',
21
+ file: contentPath.base,
22
+ },
23
+ ]
40
24
  }
41
25
 
42
- // rollup-plugin-postcss does not support dir-dependency messages
43
- // but directories can be watched in the same way as files
44
- if (message.type === 'dir-dependency' && process.env.ROLLUP_WATCH === 'true') {
45
- message = { type: 'dependency', file: message.dir }
26
+ if (process.env.ROLLUP_WATCH === 'true') {
27
+ // rollup-plugin-postcss does not support dir-dependency messages
28
+ // but directories can be watched in the same way as files
29
+ return [
30
+ {
31
+ type: 'dependency',
32
+ file: contentPath.base,
33
+ },
34
+ ]
46
35
  }
47
36
 
48
- return message
37
+ return [
38
+ {
39
+ type: 'dir-dependency',
40
+ dir: contentPath.base,
41
+ glob: contentPath.glob,
42
+ },
43
+ ]
49
44
  }
@@ -0,0 +1,24 @@
1
+ import globParent from 'glob-parent'
2
+
3
+ // Based on `glob-base`
4
+ // https://github.com/micromatch/glob-base/blob/master/index.js
5
+ export function parseGlob(pattern) {
6
+ let glob = pattern
7
+ let base = globParent(pattern)
8
+
9
+ if (base !== '.') {
10
+ glob = pattern.substr(base.length)
11
+ if (glob.charAt(0) === '/') {
12
+ glob = glob.substr(1)
13
+ }
14
+ }
15
+
16
+ if (glob.substr(0, 2) === './') {
17
+ glob = glob.substr(2)
18
+ }
19
+ if (glob.charAt(0) === '/') {
20
+ glob = glob.substr(1)
21
+ }
22
+
23
+ return { base, glob }
24
+ }
@@ -1,4 +1,3 @@
1
- import selectorParser from 'postcss-selector-parser'
2
1
  import escapeCommas from './escapeCommas'
3
2
  import { withAlphaValue } from './withAlphaVariable'
4
3
  import {
@@ -18,21 +17,22 @@ import {
18
17
  shadow,
19
18
  } from './dataTypes'
20
19
  import negateValue from './negateValue'
21
-
20
+ import { backgroundSize } from './validateFormalSyntax'
21
+ import { flagEnabled } from '../featureFlags.js'
22
+
23
+ /**
24
+ * @param {import('postcss-selector-parser').Container} selectors
25
+ * @param {(className: string) => string} updateClass
26
+ * @returns {string}
27
+ */
22
28
  export function updateAllClasses(selectors, updateClass) {
23
- let parser = selectorParser((selectors) => {
24
- selectors.walkClasses((sel) => {
25
- let updatedClass = updateClass(sel.value)
26
- sel.value = updatedClass
27
- if (sel.raws && sel.raws.value) {
28
- sel.raws.value = escapeCommas(sel.raws.value)
29
- }
30
- })
31
- })
32
-
33
- let result = parser.processSync(selectors)
29
+ selectors.walkClasses((sel) => {
30
+ sel.value = updateClass(sel.value)
34
31
 
35
- return result
32
+ if (sel.raws && sel.raws.value) {
33
+ sel.raws.value = escapeCommas(sel.raws.value)
34
+ }
35
+ })
36
36
  }
37
37
 
38
38
  function resolveArbitraryValue(modifier, validate) {
@@ -85,22 +85,63 @@ function isArbitraryValue(input) {
85
85
  return input.startsWith('[') && input.endsWith(']')
86
86
  }
87
87
 
88
- function splitAlpha(modifier) {
88
+ function splitUtilityModifier(modifier) {
89
89
  let slashIdx = modifier.lastIndexOf('/')
90
90
 
91
+ // If the `/` is inside an arbitrary, we want to find the previous one if any
92
+ // This logic probably isn't perfect but it should work for most cases
93
+ let arbitraryStartIdx = modifier.lastIndexOf('[', slashIdx)
94
+ let arbitraryEndIdx = modifier.indexOf(']', slashIdx)
95
+
96
+ let isNextToArbitrary = modifier[slashIdx - 1] === ']' || modifier[slashIdx + 1] === '['
97
+
98
+ // Backtrack to the previous `/` if the one we found was inside an arbitrary
99
+ if (!isNextToArbitrary) {
100
+ if (arbitraryStartIdx !== -1 && arbitraryEndIdx !== -1) {
101
+ if (arbitraryStartIdx < slashIdx && slashIdx < arbitraryEndIdx) {
102
+ slashIdx = modifier.lastIndexOf('/', arbitraryStartIdx)
103
+ }
104
+ }
105
+ }
106
+
91
107
  if (slashIdx === -1 || slashIdx === modifier.length - 1) {
92
- return [modifier]
108
+ return [modifier, undefined]
109
+ }
110
+
111
+ let arbitrary = isArbitraryValue(modifier)
112
+
113
+ // The modifier could be of the form `[foo]/[bar]`
114
+ // We want to handle this case properly
115
+ // without affecting `[foo/bar]`
116
+ if (arbitrary && !modifier.includes(']/[')) {
117
+ return [modifier, undefined]
93
118
  }
94
119
 
95
120
  return [modifier.slice(0, slashIdx), modifier.slice(slashIdx + 1)]
96
121
  }
97
122
 
123
+ export function parseColorFormat(value) {
124
+ if (typeof value === 'string' && value.includes('<alpha-value>')) {
125
+ let oldValue = value
126
+
127
+ return ({ opacityValue = 1 }) => oldValue.replace('<alpha-value>', opacityValue)
128
+ }
129
+
130
+ return value
131
+ }
132
+
133
+ function unwrapArbitraryModifier(modifier) {
134
+ return normalize(modifier.slice(1, -1))
135
+ }
136
+
98
137
  export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
99
138
  if (options.values?.[modifier] !== undefined) {
100
- return options.values?.[modifier]
139
+ return parseColorFormat(options.values?.[modifier])
101
140
  }
102
141
 
103
- let [color, alpha] = splitAlpha(modifier)
142
+ // TODO: Hoist this up to getMatchingTypes or something
143
+ // We do this here because we need the alpha value (if any)
144
+ let [color, alpha] = splitUtilityModifier(modifier)
104
145
 
105
146
  if (alpha !== undefined) {
106
147
  let normalizedColor =
@@ -110,8 +151,10 @@ export function asColor(modifier, options = {}, { tailwindConfig = {} } = {}) {
110
151
  return undefined
111
152
  }
112
153
 
154
+ normalizedColor = parseColorFormat(normalizedColor)
155
+
113
156
  if (isArbitraryValue(alpha)) {
114
- return withAlphaValue(normalizedColor, alpha.slice(1, -1))
157
+ return withAlphaValue(normalizedColor, unwrapArbitraryModifier(alpha))
115
158
  }
116
159
 
117
160
  if (tailwindConfig.theme?.opacity?.[alpha] === undefined) {
@@ -134,7 +177,7 @@ function guess(validate) {
134
177
  }
135
178
  }
136
179
 
137
- let typeMap = {
180
+ export let typeMap = {
138
181
  any: asValue,
139
182
  color: asColor,
140
183
  url: guess(url),
@@ -150,6 +193,7 @@ let typeMap = {
150
193
  'absolute-size': guess(absoluteSize),
151
194
  'relative-size': guess(relativeSize),
152
195
  shadow: guess(shadow),
196
+ size: guess(backgroundSize),
153
197
  }
154
198
 
155
199
  let supportedTypes = Object.keys(typeMap)
@@ -161,6 +205,20 @@ function splitAtFirst(input, delim) {
161
205
  }
162
206
 
163
207
  export function coerceValue(types, modifier, options, tailwindConfig) {
208
+ if (options.values && modifier in options.values) {
209
+ for (let { type } of types ?? []) {
210
+ let result = typeMap[type](modifier, options, {
211
+ tailwindConfig,
212
+ })
213
+
214
+ if (result === undefined) {
215
+ continue
216
+ }
217
+
218
+ return [result, type, null]
219
+ }
220
+ }
221
+
164
222
  if (isArbitraryValue(modifier)) {
165
223
  let arbitraryValue = modifier.slice(1, -1)
166
224
  let [explicitType, value] = splitAtFirst(arbitraryValue, ':')
@@ -178,15 +236,72 @@ export function coerceValue(types, modifier, options, tailwindConfig) {
178
236
  }
179
237
 
180
238
  if (value.length > 0 && supportedTypes.includes(explicitType)) {
181
- return [asValue(`[${value}]`, options), explicitType]
239
+ return [asValue(`[${value}]`, options), explicitType, null]
182
240
  }
183
241
  }
184
242
 
243
+ let matches = getMatchingTypes(types, modifier, options, tailwindConfig)
244
+
185
245
  // Find first matching type
186
- for (let type of [].concat(types)) {
187
- let result = typeMap[type](modifier, options, { tailwindConfig })
188
- if (result) return [result, type]
246
+ for (let match of matches) {
247
+ return match
189
248
  }
190
249
 
191
250
  return []
192
251
  }
252
+
253
+ /**
254
+ *
255
+ * @param {{type: string}[]} types
256
+ * @param {string} rawModifier
257
+ * @param {any} options
258
+ * @param {any} tailwindConfig
259
+ * @returns {Iterator<[value: string, type: string, modifier: string | null]>}
260
+ */
261
+ export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) {
262
+ let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers')
263
+
264
+ let [modifier, utilityModifier] = splitUtilityModifier(rawModifier)
265
+
266
+ let canUseUtilityModifier =
267
+ modifiersEnabled &&
268
+ options.modifiers != null &&
269
+ (options.modifiers === 'any' ||
270
+ (typeof options.modifiers === 'object' &&
271
+ ((utilityModifier && isArbitraryValue(utilityModifier)) ||
272
+ utilityModifier in options.modifiers)))
273
+
274
+ if (!canUseUtilityModifier) {
275
+ modifier = rawModifier
276
+ utilityModifier = undefined
277
+ }
278
+
279
+ if (utilityModifier !== undefined && modifier === '') {
280
+ modifier = 'DEFAULT'
281
+ }
282
+
283
+ // Check the full value first
284
+ // TODO: Move to asValue… somehow
285
+ if (utilityModifier !== undefined) {
286
+ if (typeof options.modifiers === 'object') {
287
+ let configValue = options.modifiers?.[utilityModifier] ?? null
288
+ if (configValue !== null) {
289
+ utilityModifier = configValue
290
+ } else if (isArbitraryValue(utilityModifier)) {
291
+ utilityModifier = unwrapArbitraryModifier(utilityModifier)
292
+ }
293
+ }
294
+ }
295
+
296
+ for (let { type } of types ?? []) {
297
+ let result = typeMap[type](modifier, options, {
298
+ tailwindConfig,
299
+ })
300
+
301
+ if (result === undefined) {
302
+ continue
303
+ }
304
+
305
+ yield [result, type, utilityModifier ?? null]
306
+ }
307
+ }
@@ -1,12 +1,33 @@
1
1
  import parser from 'postcss-selector-parser'
2
- import { tap } from './tap'
3
-
4
- export default function (prefix, selector) {
5
- return parser((selectors) => {
6
- selectors.walkClasses((classSelector) => {
7
- tap(classSelector.value, (baseClass) => {
8
- classSelector.value = `${prefix}${baseClass}`
9
- })
10
- })
11
- }).processSync(selector)
2
+
3
+ /**
4
+ * @template {string | import('postcss-selector-parser').Root} T
5
+ *
6
+ * Prefix all classes in the selector with the given prefix
7
+ *
8
+ * It can take either a string or a selector AST and will return the same type
9
+ *
10
+ * @param {string} prefix
11
+ * @param {T} selector
12
+ * @param {boolean} prependNegative
13
+ * @returns {T}
14
+ */
15
+ export default function (prefix, selector, prependNegative = false) {
16
+ if (prefix === '') {
17
+ return selector
18
+ }
19
+
20
+ /** @type {import('postcss-selector-parser').Root} */
21
+ let ast = typeof selector === 'string' ? parser().astSync(selector) : selector
22
+
23
+ ast.walkClasses((classSelector) => {
24
+ let baseClass = classSelector.value
25
+ let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-')
26
+
27
+ classSelector.value = shouldPlaceNegativeBeforePrefix
28
+ ? `-${prefix}${baseClass.slice(1)}`
29
+ : `${prefix}${baseClass}`
30
+ })
31
+
32
+ return typeof selector === 'string' ? ast.toString() : ast
12
33
  }