tailwindcss 0.0.0-insiders.e2d5f21 → 0.0.0-insiders.e302ef1
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 +244 -3
- package/LICENSE +1 -2
- package/README.md +8 -4
- package/colors.js +2 -1
- package/defaultConfig.js +2 -1
- package/defaultTheme.js +2 -1
- package/lib/cli.js +123 -88
- package/lib/corePlugins.js +288 -360
- package/lib/css/preflight.css +4 -4
- package/lib/featureFlags.js +4 -5
- package/lib/index.js +12 -3
- package/lib/lib/cacheInvalidation.js +69 -0
- package/lib/lib/collapseAdjacentRules.js +14 -1
- package/lib/lib/collapseDuplicateDeclarations.js +52 -1
- package/lib/lib/defaultExtractor.js +44 -0
- package/lib/lib/evaluateTailwindFunctions.js +1 -1
- package/lib/lib/expandApplyAtRules.js +265 -60
- package/lib/lib/expandTailwindAtRules.js +63 -48
- package/lib/lib/generateRules.js +136 -34
- package/lib/lib/normalizeTailwindDirectives.js +10 -2
- package/lib/lib/partitionApplyAtRules.js +53 -0
- package/lib/lib/resolveDefaultsAtRules.js +30 -12
- package/lib/lib/setupContextUtils.js +137 -81
- package/lib/lib/setupTrackingContext.js +8 -7
- package/lib/lib/sharedState.js +38 -5
- package/{nesting → lib/postcss-plugins/nesting}/README.md +0 -0
- package/lib/postcss-plugins/nesting/index.js +17 -0
- package/lib/postcss-plugins/nesting/plugin.js +85 -0
- package/lib/processTailwindFeatures.js +10 -2
- package/lib/util/cloneNodes.js +12 -1
- package/lib/util/color.js +23 -8
- package/lib/util/createPlugin.js +1 -2
- package/lib/util/createUtilityPlugin.js +4 -8
- package/lib/util/dataTypes.js +4 -2
- package/lib/util/defaults.js +6 -0
- package/lib/util/flattenColorPalette.js +1 -3
- package/lib/util/log.js +10 -6
- package/lib/util/normalizeConfig.js +47 -15
- package/lib/util/normalizeScreens.js +6 -5
- package/lib/util/parseBoxShadowValue.js +44 -4
- package/lib/util/pluginUtils.js +6 -13
- package/lib/util/prefixSelector.js +4 -5
- package/lib/util/resolveConfig.js +48 -27
- package/lib/util/resolveConfigPath.js +1 -2
- package/lib/util/toColorValue.js +1 -2
- package/lib/util/toPath.js +6 -1
- package/lib/util/transformThemeValue.js +4 -8
- package/nesting/index.js +2 -12
- package/package.json +28 -33
- package/peers/index.js +3209 -4239
- package/plugin.js +2 -1
- package/resolveConfig.js +2 -1
- package/src/cli.js +62 -15
- package/src/corePlugins.js +212 -217
- package/src/css/preflight.css +4 -4
- package/src/featureFlags.js +3 -3
- package/src/index.js +14 -6
- package/src/lib/cacheInvalidation.js +52 -0
- package/src/lib/collapseAdjacentRules.js +16 -1
- package/src/lib/collapseDuplicateDeclarations.js +66 -1
- package/src/lib/defaultExtractor.js +50 -0
- package/src/lib/evaluateTailwindFunctions.js +1 -1
- package/src/lib/expandApplyAtRules.js +285 -56
- package/src/lib/expandTailwindAtRules.js +75 -37
- package/src/lib/generateRules.js +121 -27
- package/src/lib/normalizeTailwindDirectives.js +7 -1
- package/src/lib/partitionApplyAtRules.js +52 -0
- package/src/lib/resolveDefaultsAtRules.js +35 -10
- package/src/lib/setupContextUtils.js +127 -45
- package/src/lib/setupTrackingContext.js +8 -7
- package/src/lib/sharedState.js +42 -4
- package/src/postcss-plugins/nesting/README.md +42 -0
- package/src/postcss-plugins/nesting/index.js +13 -0
- package/src/postcss-plugins/nesting/plugin.js +80 -0
- package/src/processTailwindFeatures.js +12 -2
- package/src/util/cloneNodes.js +14 -1
- package/src/util/color.js +20 -7
- package/src/util/dataTypes.js +7 -5
- package/src/util/defaults.js +6 -0
- package/src/util/log.js +10 -6
- package/src/util/normalizeConfig.js +24 -3
- package/src/util/normalizeScreens.js +6 -3
- package/src/util/parseBoxShadowValue.js +51 -3
- package/src/util/pluginUtils.js +1 -1
- package/src/util/prefixSelector.js +7 -5
- package/src/util/resolveConfig.js +41 -1
- package/src/util/toPath.js +23 -1
- package/stubs/defaultConfig.stub.js +2 -2
- package/lib/lib/setupWatchingContext.js +0 -288
- package/nesting/plugin.js +0 -41
- package/src/lib/setupWatchingContext.js +0 -311
package/src/util/dataTypes.js
CHANGED
|
@@ -80,11 +80,13 @@ let lengthUnits = [
|
|
|
80
80
|
]
|
|
81
81
|
let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`
|
|
82
82
|
export function length(value) {
|
|
83
|
-
return (
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
return value.split(UNDERSCORE).every((part) => {
|
|
84
|
+
return (
|
|
85
|
+
part === '0' ||
|
|
86
|
+
new RegExp(`${lengthUnitsPattern}$`).test(part) ||
|
|
87
|
+
cssFunctions.some((fn) => new RegExp(`^${fn}\\(.+?${lengthUnitsPattern}`).test(part))
|
|
88
|
+
)
|
|
89
|
+
})
|
|
88
90
|
}
|
|
89
91
|
|
|
90
92
|
let lineWidths = new Set(['thin', 'medium', 'thick'])
|
package/src/util/defaults.js
CHANGED
package/src/util/log.js
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
import
|
|
1
|
+
import colors from 'picocolors'
|
|
2
2
|
|
|
3
3
|
let alreadyShown = new Set()
|
|
4
4
|
|
|
5
|
-
function log(
|
|
5
|
+
function log(type, messages, key) {
|
|
6
6
|
if (process.env.JEST_WORKER_ID !== undefined) return
|
|
7
7
|
|
|
8
8
|
if (key && alreadyShown.has(key)) return
|
|
9
9
|
if (key) alreadyShown.add(key)
|
|
10
10
|
|
|
11
11
|
console.warn('')
|
|
12
|
-
messages.forEach((message) => console.warn(
|
|
12
|
+
messages.forEach((message) => console.warn(type, '-', message))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function dim(input) {
|
|
16
|
+
return colors.dim(input)
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
export default {
|
|
16
20
|
info(key, messages) {
|
|
17
|
-
log(
|
|
21
|
+
log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key]))
|
|
18
22
|
},
|
|
19
23
|
warn(key, messages) {
|
|
20
|
-
log(
|
|
24
|
+
log(colors.bold(colors.yellow('warn')), ...(Array.isArray(key) ? [key] : [messages, key]))
|
|
21
25
|
},
|
|
22
26
|
risk(key, messages) {
|
|
23
|
-
log(
|
|
27
|
+
log(colors.bold(colors.magenta('risk')), ...(Array.isArray(key) ? [key] : [messages, key]))
|
|
24
28
|
},
|
|
25
29
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import log from './log'
|
|
1
|
+
import log, { dim } from './log'
|
|
2
2
|
|
|
3
3
|
export function normalizeConfig(config) {
|
|
4
4
|
// Quick structure validation
|
|
@@ -124,7 +124,7 @@ export function normalizeConfig(config) {
|
|
|
124
124
|
log.warn('purge-deprecation', [
|
|
125
125
|
'The `purge`/`content` options have changed in Tailwind CSS v3.0.',
|
|
126
126
|
'Update your configuration file to eliminate this warning.',
|
|
127
|
-
|
|
127
|
+
'https://tailwindcss.com/docs/upgrade-guide#configure-content-sources',
|
|
128
128
|
])
|
|
129
129
|
}
|
|
130
130
|
|
|
@@ -145,7 +145,7 @@ export function normalizeConfig(config) {
|
|
|
145
145
|
log.warn('prefix-function', [
|
|
146
146
|
'As of Tailwind CSS v3.0, `prefix` cannot be a function.',
|
|
147
147
|
'Update `prefix` in your configuration to be a string to eliminate this warning.',
|
|
148
|
-
|
|
148
|
+
'https://tailwindcss.com/docs/upgrade-guide#prefix-cannot-be-a-function',
|
|
149
149
|
])
|
|
150
150
|
config.prefix = ''
|
|
151
151
|
} else {
|
|
@@ -245,5 +245,26 @@ export function normalizeConfig(config) {
|
|
|
245
245
|
})(),
|
|
246
246
|
}
|
|
247
247
|
|
|
248
|
+
// Validate globs to prevent bogus globs.
|
|
249
|
+
// E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html`
|
|
250
|
+
for (let file of config.content.files) {
|
|
251
|
+
if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) {
|
|
252
|
+
log.warn('invalid-glob-braces', [
|
|
253
|
+
`The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`,
|
|
254
|
+
`Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`,
|
|
255
|
+
// TODO: Add https://tw.wtf/invalid-glob-braces
|
|
256
|
+
])
|
|
257
|
+
break
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (config.content.files.length === 0) {
|
|
262
|
+
log.warn('content-problems', [
|
|
263
|
+
'The `content` option in your Tailwind CSS configuration is missing or empty.',
|
|
264
|
+
'Configure your content sources or your generated CSS will be missing styles.',
|
|
265
|
+
'https://tailwindcss.com/docs/content-configuration',
|
|
266
|
+
])
|
|
267
|
+
}
|
|
268
|
+
|
|
248
269
|
return config
|
|
249
270
|
}
|
|
@@ -7,14 +7,17 @@
|
|
|
7
7
|
* - { sm: '100px', md: '200px' } // Object with string values
|
|
8
8
|
* - { sm: { min: '100px' }, md: { max: '100px' } } // Object with object values
|
|
9
9
|
* - { sm: [{ min: '100px' }, { max: '200px' }] } // Object with object array (multiple values)
|
|
10
|
-
* - [['sm', '100px'], ['md', '200px']] // Tuple object
|
|
11
10
|
*
|
|
12
11
|
* Output(s):
|
|
13
12
|
* - [{ name: 'sm', values: [{ min: '100px', max: '200px' }] }] // List of objects, that contains multiple values
|
|
14
13
|
*/
|
|
15
|
-
export function normalizeScreens(screens) {
|
|
14
|
+
export function normalizeScreens(screens, root = true) {
|
|
16
15
|
if (Array.isArray(screens)) {
|
|
17
16
|
return screens.map((screen) => {
|
|
17
|
+
if (root && Array.isArray(screen)) {
|
|
18
|
+
throw new Error('The tuple syntax is not supported for `screens`.')
|
|
19
|
+
}
|
|
20
|
+
|
|
18
21
|
if (typeof screen === 'string') {
|
|
19
22
|
return { name: screen.toString(), values: [{ min: screen, max: undefined }] }
|
|
20
23
|
}
|
|
@@ -34,7 +37,7 @@ export function normalizeScreens(screens) {
|
|
|
34
37
|
})
|
|
35
38
|
}
|
|
36
39
|
|
|
37
|
-
return normalizeScreens(Object.entries(screens ?? {}))
|
|
40
|
+
return normalizeScreens(Object.entries(screens ?? {}), false)
|
|
38
41
|
}
|
|
39
42
|
|
|
40
43
|
function resolveValue({ 'min-width': _minWidth, min = _minWidth, max, raw } = {}) {
|
|
@@ -1,10 +1,58 @@
|
|
|
1
1
|
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
2
|
let SPACE = /\ +(?![^(]*\))/g // Similar to the one above, but with spaces instead.
|
|
4
|
-
let LENGTH = /^-?(\d+)(.*?)$/g
|
|
3
|
+
let LENGTH = /^-?(\d+|\.\d+)(.*?)$/g
|
|
4
|
+
|
|
5
|
+
let SPECIALS = /[(),]/g
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* This splits a string on top-level commas.
|
|
9
|
+
*
|
|
10
|
+
* Regex doesn't support recursion (at least not the JS-flavored version).
|
|
11
|
+
* So we have to use a tiny state machine to keep track of paren vs comma
|
|
12
|
+
* placement. Before we'd only exclude commas from the inner-most nested
|
|
13
|
+
* set of parens rather than any commas that were not contained in parens
|
|
14
|
+
* at all which is the intended behavior here.
|
|
15
|
+
*
|
|
16
|
+
* Expected behavior:
|
|
17
|
+
* var(--a, 0 0 1px rgb(0, 0, 0)), 0 0 1px rgb(0, 0, 0)
|
|
18
|
+
* ─┬─ ┬ ┬ ┬
|
|
19
|
+
* x x x ╰──────── Split because top-level
|
|
20
|
+
* ╰──────────────┴──┴───────────── Ignored b/c inside >= 1 levels of parens
|
|
21
|
+
*
|
|
22
|
+
* @param {string} input
|
|
23
|
+
*/
|
|
24
|
+
function* splitByTopLevelCommas(input) {
|
|
25
|
+
SPECIALS.lastIndex = -1
|
|
26
|
+
|
|
27
|
+
let depth = 0
|
|
28
|
+
let lastIndex = 0
|
|
29
|
+
let found = false
|
|
30
|
+
|
|
31
|
+
// Find all parens & commas
|
|
32
|
+
// And only split on commas if they're top-level
|
|
33
|
+
for (let match of input.matchAll(SPECIALS)) {
|
|
34
|
+
if (match[0] === '(') depth++
|
|
35
|
+
if (match[0] === ')') depth--
|
|
36
|
+
if (match[0] === ',' && depth === 0) {
|
|
37
|
+
found = true
|
|
38
|
+
|
|
39
|
+
yield input.substring(lastIndex, match.index)
|
|
40
|
+
lastIndex = match.index + match[0].length
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Provide the last segment of the string if available
|
|
45
|
+
// Otherwise the whole string since no commas were found
|
|
46
|
+
// This mirrors the behavior of string.split()
|
|
47
|
+
if (found) {
|
|
48
|
+
yield input.substring(lastIndex)
|
|
49
|
+
} else {
|
|
50
|
+
yield input
|
|
51
|
+
}
|
|
52
|
+
}
|
|
5
53
|
|
|
6
54
|
export function parseBoxShadowValue(input) {
|
|
7
|
-
let shadows =
|
|
55
|
+
let shadows = Array.from(splitByTopLevelCommas(input))
|
|
8
56
|
return shadows.map((shadow) => {
|
|
9
57
|
let value = shadow.trim()
|
|
10
58
|
let result = { raw: value }
|
package/src/util/pluginUtils.js
CHANGED
|
@@ -185,7 +185,7 @@ export function coerceValue(types, modifier, options, tailwindConfig) {
|
|
|
185
185
|
// Find first matching type
|
|
186
186
|
for (let type of [].concat(types)) {
|
|
187
187
|
let result = typeMap[type](modifier, options, { tailwindConfig })
|
|
188
|
-
if (result) return [result, type]
|
|
188
|
+
if (result !== undefined) return [result, type]
|
|
189
189
|
}
|
|
190
190
|
|
|
191
191
|
return []
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import parser from 'postcss-selector-parser'
|
|
2
|
-
import { tap } from './tap'
|
|
3
2
|
|
|
4
|
-
export default function (prefix, selector) {
|
|
3
|
+
export default function (prefix, selector, prependNegative = false) {
|
|
5
4
|
return parser((selectors) => {
|
|
6
5
|
selectors.walkClasses((classSelector) => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
let baseClass = classSelector.value
|
|
7
|
+
let shouldPlaceNegativeBeforePrefix = prependNegative && baseClass.startsWith('-')
|
|
8
|
+
|
|
9
|
+
classSelector.value = shouldPlaceNegativeBeforePrefix
|
|
10
|
+
? `-${prefix}${baseClass.slice(1)}`
|
|
11
|
+
: `${prefix}${baseClass}`
|
|
10
12
|
})
|
|
11
13
|
}).processSync(selector)
|
|
12
14
|
}
|
|
@@ -6,6 +6,8 @@ import colors from '../public/colors'
|
|
|
6
6
|
import { defaults } from './defaults'
|
|
7
7
|
import { toPath } from './toPath'
|
|
8
8
|
import { normalizeConfig } from './normalizeConfig'
|
|
9
|
+
import isPlainObject from './isPlainObject'
|
|
10
|
+
import { cloneDeep } from './cloneDeep'
|
|
9
11
|
|
|
10
12
|
function isFunction(input) {
|
|
11
13
|
return typeof input === 'function'
|
|
@@ -64,6 +66,36 @@ const configUtils = {
|
|
|
64
66
|
{}
|
|
65
67
|
)
|
|
66
68
|
},
|
|
69
|
+
rgb(property) {
|
|
70
|
+
if (!property.startsWith('--')) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
'The rgb() helper requires a custom property name to be passed as the first argument.'
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return ({ opacityValue }) => {
|
|
77
|
+
if (opacityValue === undefined || opacityValue === 1) {
|
|
78
|
+
return `rgb(var(${property}) / 1.0)`
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return `rgb(var(${property}) / ${opacityValue})`
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
hsl(property) {
|
|
85
|
+
if (!property.startsWith('--')) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
'The hsl() helper requires a custom property name to be passed as the first argument.'
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return ({ opacityValue }) => {
|
|
92
|
+
if (opacityValue === undefined || opacityValue === 1) {
|
|
93
|
+
return `hsl(var(${property}) / 1)`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return `hsl(var(${property}) / ${opacityValue})`
|
|
97
|
+
}
|
|
98
|
+
},
|
|
67
99
|
}
|
|
68
100
|
|
|
69
101
|
function value(valueToResolve, ...args) {
|
|
@@ -144,7 +176,15 @@ function resolveFunctionKeys(object) {
|
|
|
144
176
|
val = isFunction(val) ? val(resolvePath, configUtils) : val
|
|
145
177
|
}
|
|
146
178
|
|
|
147
|
-
|
|
179
|
+
if (val === undefined) {
|
|
180
|
+
return defaultValue
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (isPlainObject(val)) {
|
|
184
|
+
return cloneDeep(val)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return val
|
|
148
188
|
}
|
|
149
189
|
|
|
150
190
|
resolvePath.theme = resolvePath
|
package/src/util/toPath.js
CHANGED
|
@@ -1,4 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a path string into an array of path segments.
|
|
3
|
+
*
|
|
4
|
+
* Square bracket notation `a[b]` may be used to "escape" dots that would otherwise be interpreted as path separators.
|
|
5
|
+
*
|
|
6
|
+
* Example:
|
|
7
|
+
* a -> ['a]
|
|
8
|
+
* a.b.c -> ['a', 'b', 'c']
|
|
9
|
+
* a[b].c -> ['a', 'b', 'c']
|
|
10
|
+
* a[b.c].e.f -> ['a', 'b.c', 'e', 'f']
|
|
11
|
+
* a[b][c][d] -> ['a', 'b', 'c', 'd']
|
|
12
|
+
*
|
|
13
|
+
* @param {string|string[]} path
|
|
14
|
+
**/
|
|
1
15
|
export function toPath(path) {
|
|
2
16
|
if (Array.isArray(path)) return path
|
|
3
|
-
|
|
17
|
+
|
|
18
|
+
let openBrackets = path.split('[').length - 1
|
|
19
|
+
let closedBrackets = path.split(']').length - 1
|
|
20
|
+
|
|
21
|
+
if (openBrackets !== closedBrackets) {
|
|
22
|
+
throw new Error(`Path is invalid. Has unbalanced brackets: ${path}`)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return path.split(/\.(?![^\[]*\])|[\[\]]/g).filter(Boolean)
|
|
4
26
|
}
|
|
@@ -854,8 +854,8 @@ module.exports = {
|
|
|
854
854
|
none: 'none',
|
|
855
855
|
all: 'all',
|
|
856
856
|
DEFAULT:
|
|
857
|
-
'background-color, border-color, color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter',
|
|
858
|
-
colors: 'background-color, border-color, color, fill, stroke',
|
|
857
|
+
'color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter',
|
|
858
|
+
colors: 'color, background-color, border-color, text-decoration-color, fill, stroke',
|
|
859
859
|
opacity: 'opacity',
|
|
860
860
|
shadow: 'box-shadow',
|
|
861
861
|
transform: 'transform',
|
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", {
|
|
3
|
-
value: true
|
|
4
|
-
});
|
|
5
|
-
exports.default = setupWatchingContext;
|
|
6
|
-
var _fs = _interopRequireDefault(require("fs"));
|
|
7
|
-
var _path = _interopRequireDefault(require("path"));
|
|
8
|
-
var _tmp = _interopRequireDefault(require("tmp"));
|
|
9
|
-
var _chokidar = _interopRequireDefault(require("chokidar"));
|
|
10
|
-
var _fastGlob = _interopRequireDefault(require("fast-glob"));
|
|
11
|
-
var _quickLru = _interopRequireDefault(require("quick-lru"));
|
|
12
|
-
var _normalizePath = _interopRequireDefault(require("normalize-path"));
|
|
13
|
-
var _hashConfig = _interopRequireDefault(require("../util/hashConfig"));
|
|
14
|
-
var _log = _interopRequireDefault(require("../util/log"));
|
|
15
|
-
var _getModuleDependencies = _interopRequireDefault(require("../lib/getModuleDependencies"));
|
|
16
|
-
var _resolveConfig = _interopRequireDefault(require("../public/resolve-config"));
|
|
17
|
-
var _resolveConfigPath = _interopRequireDefault(require("../util/resolveConfigPath"));
|
|
18
|
-
var _setupContextUtils = require("./setupContextUtils");
|
|
19
|
-
function _interopRequireDefault(obj) {
|
|
20
|
-
return obj && obj.__esModule ? obj : {
|
|
21
|
-
default: obj
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
// This is used to trigger rebuilds. Just updating the timestamp
|
|
25
|
-
// is significantly faster than actually writing to the file (10x).
|
|
26
|
-
function touch(filename) {
|
|
27
|
-
let time = new Date();
|
|
28
|
-
try {
|
|
29
|
-
_fs.default.utimesSync(filename, time, time);
|
|
30
|
-
} catch (err) {
|
|
31
|
-
_fs.default.closeSync(_fs.default.openSync(filename, 'w'));
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
let watchers = new WeakMap();
|
|
35
|
-
function getWatcher(context) {
|
|
36
|
-
if (watchers.has(context)) {
|
|
37
|
-
return watchers.get(context);
|
|
38
|
-
}
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
function setWatcher(context, watcher) {
|
|
42
|
-
return watchers.set(context, watcher);
|
|
43
|
-
}
|
|
44
|
-
let touchFiles = new WeakMap();
|
|
45
|
-
function getTouchFile(context) {
|
|
46
|
-
if (touchFiles.has(context)) {
|
|
47
|
-
return touchFiles.get(context);
|
|
48
|
-
}
|
|
49
|
-
return null;
|
|
50
|
-
}
|
|
51
|
-
function setTouchFile(context, touchFile) {
|
|
52
|
-
return touchFiles.set(context, touchFile);
|
|
53
|
-
}
|
|
54
|
-
let configPaths = new WeakMap();
|
|
55
|
-
function getConfigPath(context, configOrPath) {
|
|
56
|
-
if (!configPaths.has(context)) {
|
|
57
|
-
configPaths.set(context, (0, _resolveConfigPath).default(configOrPath));
|
|
58
|
-
}
|
|
59
|
-
return configPaths.get(context);
|
|
60
|
-
}
|
|
61
|
-
function rebootWatcher(context, configPath, configDependencies, candidateFiles) {
|
|
62
|
-
let touchFile = getTouchFile(context);
|
|
63
|
-
if (touchFile === null) {
|
|
64
|
-
touchFile = _tmp.default.fileSync().name;
|
|
65
|
-
setTouchFile(context, touchFile);
|
|
66
|
-
touch(touchFile);
|
|
67
|
-
}
|
|
68
|
-
let watcher = getWatcher(context);
|
|
69
|
-
Promise.resolve(watcher ? watcher.close() : null).then(()=>{
|
|
70
|
-
_log.default.info([
|
|
71
|
-
'Tailwind CSS is watching for changes...',
|
|
72
|
-
'https://tailwindcss.com/docs/just-in-time-mode#watch-mode-and-one-off-builds',
|
|
73
|
-
]);
|
|
74
|
-
watcher = _chokidar.default.watch([
|
|
75
|
-
...candidateFiles,
|
|
76
|
-
...configDependencies
|
|
77
|
-
], {
|
|
78
|
-
ignoreInitial: true,
|
|
79
|
-
awaitWriteFinish: process.platform === 'win32' ? {
|
|
80
|
-
stabilityThreshold: 50,
|
|
81
|
-
pollInterval: 10
|
|
82
|
-
} : false
|
|
83
|
-
});
|
|
84
|
-
setWatcher(context, watcher);
|
|
85
|
-
watcher.on('add', (file)=>{
|
|
86
|
-
let changedFile = _path.default.resolve('.', file);
|
|
87
|
-
let content = _fs.default.readFileSync(changedFile, 'utf8');
|
|
88
|
-
let extension = _path.default.extname(changedFile).slice(1);
|
|
89
|
-
context.changedContent.push({
|
|
90
|
-
content,
|
|
91
|
-
extension
|
|
92
|
-
});
|
|
93
|
-
touch(touchFile);
|
|
94
|
-
});
|
|
95
|
-
watcher.on('change', (file)=>{
|
|
96
|
-
// If it was a config dependency, touch the config file to trigger a new context.
|
|
97
|
-
// This is not really that clean of a solution but it's the fastest, because we
|
|
98
|
-
// can do a very quick check on each build to see if the config has changed instead
|
|
99
|
-
// of having to get all of the module dependencies and check every timestamp each
|
|
100
|
-
// time.
|
|
101
|
-
if (configDependencies.has(file)) {
|
|
102
|
-
for (let dependency of configDependencies){
|
|
103
|
-
delete require.cache[require.resolve(dependency)];
|
|
104
|
-
}
|
|
105
|
-
touch(configPath);
|
|
106
|
-
} else {
|
|
107
|
-
let changedFile = _path.default.resolve('.', file);
|
|
108
|
-
let content = _fs.default.readFileSync(changedFile, 'utf8');
|
|
109
|
-
let extension = _path.default.extname(changedFile).slice(1);
|
|
110
|
-
context.changedContent.push({
|
|
111
|
-
content,
|
|
112
|
-
extension
|
|
113
|
-
});
|
|
114
|
-
touch(touchFile);
|
|
115
|
-
}
|
|
116
|
-
});
|
|
117
|
-
watcher.on('unlink', (file)=>{
|
|
118
|
-
// Touch the config file if any of the dependencies are deleted.
|
|
119
|
-
if (configDependencies.has(file)) {
|
|
120
|
-
for (let dependency of configDependencies){
|
|
121
|
-
delete require.cache[require.resolve(dependency)];
|
|
122
|
-
}
|
|
123
|
-
touch(configPath);
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
let configPathCache = new _quickLru.default({
|
|
129
|
-
maxSize: 100
|
|
130
|
-
});
|
|
131
|
-
let configDependenciesCache = new WeakMap();
|
|
132
|
-
function getConfigDependencies(context) {
|
|
133
|
-
if (!configDependenciesCache.has(context)) {
|
|
134
|
-
configDependenciesCache.set(context, new Set());
|
|
135
|
-
}
|
|
136
|
-
return configDependenciesCache.get(context);
|
|
137
|
-
}
|
|
138
|
-
let candidateFilesCache = new WeakMap();
|
|
139
|
-
function getCandidateFiles(context, tailwindConfig) {
|
|
140
|
-
if (candidateFilesCache.has(context)) {
|
|
141
|
-
return candidateFilesCache.get(context);
|
|
142
|
-
}
|
|
143
|
-
let candidateFiles = tailwindConfig.content.files.filter((item)=>typeof item === 'string'
|
|
144
|
-
).map((contentPath)=>(0, _normalizePath).default(contentPath)
|
|
145
|
-
);
|
|
146
|
-
return candidateFilesCache.set(context, candidateFiles).get(context);
|
|
147
|
-
}
|
|
148
|
-
// Get the config object based on a path
|
|
149
|
-
function getTailwindConfig(configOrPath) {
|
|
150
|
-
let userConfigPath = (0, _resolveConfigPath).default(configOrPath);
|
|
151
|
-
if (userConfigPath !== null) {
|
|
152
|
-
let [prevConfig, prevModified = -Infinity, prevConfigHash] = configPathCache.get(userConfigPath) || [];
|
|
153
|
-
let modified = _fs.default.statSync(userConfigPath).mtimeMs;
|
|
154
|
-
// It hasn't changed (based on timestamp)
|
|
155
|
-
if (modified <= prevModified) {
|
|
156
|
-
return [
|
|
157
|
-
prevConfig,
|
|
158
|
-
userConfigPath,
|
|
159
|
-
prevConfigHash,
|
|
160
|
-
[
|
|
161
|
-
userConfigPath
|
|
162
|
-
]
|
|
163
|
-
];
|
|
164
|
-
}
|
|
165
|
-
// It has changed (based on timestamp), or first run
|
|
166
|
-
delete require.cache[userConfigPath];
|
|
167
|
-
let newConfig = (0, _resolveConfig).default(require(userConfigPath));
|
|
168
|
-
let newHash = (0, _hashConfig).default(newConfig);
|
|
169
|
-
configPathCache.set(userConfigPath, [
|
|
170
|
-
newConfig,
|
|
171
|
-
modified,
|
|
172
|
-
newHash
|
|
173
|
-
]);
|
|
174
|
-
return [
|
|
175
|
-
newConfig,
|
|
176
|
-
userConfigPath,
|
|
177
|
-
newHash,
|
|
178
|
-
[
|
|
179
|
-
userConfigPath
|
|
180
|
-
]
|
|
181
|
-
];
|
|
182
|
-
}
|
|
183
|
-
// It's a plain object, not a path
|
|
184
|
-
let newConfig = (0, _resolveConfig).default(configOrPath.config === undefined ? configOrPath : configOrPath.config);
|
|
185
|
-
return [
|
|
186
|
-
newConfig,
|
|
187
|
-
null,
|
|
188
|
-
(0, _hashConfig).default(newConfig),
|
|
189
|
-
[]
|
|
190
|
-
];
|
|
191
|
-
}
|
|
192
|
-
function resolvedChangedContent(context, candidateFiles) {
|
|
193
|
-
let changedContent = context.tailwindConfig.content.files.filter((item)=>typeof item.raw === 'string'
|
|
194
|
-
).map(({ raw , extension ='html' })=>({
|
|
195
|
-
content: raw,
|
|
196
|
-
extension
|
|
197
|
-
})
|
|
198
|
-
);
|
|
199
|
-
for (let changedFile of resolveChangedFiles(context, candidateFiles)){
|
|
200
|
-
let content = _fs.default.readFileSync(changedFile, 'utf8');
|
|
201
|
-
let extension = _path.default.extname(changedFile).slice(1);
|
|
202
|
-
changedContent.push({
|
|
203
|
-
content,
|
|
204
|
-
extension
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
return changedContent;
|
|
208
|
-
}
|
|
209
|
-
let scannedContentCache = new WeakMap();
|
|
210
|
-
function resolveChangedFiles(context, candidateFiles) {
|
|
211
|
-
let changedFiles = new Set();
|
|
212
|
-
// If we're not set up and watching files ourselves, we need to do
|
|
213
|
-
// the work of grabbing all of the template files for candidate
|
|
214
|
-
// detection.
|
|
215
|
-
if (!scannedContentCache.has(context)) {
|
|
216
|
-
let files = _fastGlob.default.sync(candidateFiles);
|
|
217
|
-
for (let file of files){
|
|
218
|
-
changedFiles.add(file);
|
|
219
|
-
}
|
|
220
|
-
scannedContentCache.set(context, true);
|
|
221
|
-
}
|
|
222
|
-
return changedFiles;
|
|
223
|
-
}
|
|
224
|
-
function setupWatchingContext(configOrPath) {
|
|
225
|
-
return ({ tailwindDirectives , registerDependency })=>{
|
|
226
|
-
return (root, result)=>{
|
|
227
|
-
let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = getTailwindConfig(configOrPath);
|
|
228
|
-
let contextDependencies = new Set(configDependencies);
|
|
229
|
-
// If there are no @tailwind rules, we don't consider this CSS file or it's dependencies
|
|
230
|
-
// to be dependencies of the context. Can reuse the context even if they change.
|
|
231
|
-
// We may want to think about `@layer` being part of this trigger too, but it's tough
|
|
232
|
-
// because it's impossible for a layer in one file to end up in the actual @tailwind rule
|
|
233
|
-
// in another file since independent sources are effectively isolated.
|
|
234
|
-
if (tailwindDirectives.size > 0) {
|
|
235
|
-
// Add current css file as a context dependencies.
|
|
236
|
-
contextDependencies.add(result.opts.from);
|
|
237
|
-
// Add all css @import dependencies as context dependencies.
|
|
238
|
-
for (let message of result.messages){
|
|
239
|
-
if (message.type === 'dependency') {
|
|
240
|
-
contextDependencies.add(message.file);
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
let [context, isNewContext] = (0, _setupContextUtils).getContext(root, result, tailwindConfig, userConfigPath, tailwindConfigHash, contextDependencies);
|
|
245
|
-
let candidateFiles = getCandidateFiles(context, tailwindConfig);
|
|
246
|
-
let contextConfigDependencies = getConfigDependencies(context);
|
|
247
|
-
for (let file of configDependencies){
|
|
248
|
-
registerDependency({
|
|
249
|
-
type: 'dependency',
|
|
250
|
-
file
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
context.disposables.push((oldContext)=>{
|
|
254
|
-
let watcher = getWatcher(oldContext);
|
|
255
|
-
if (watcher !== null) {
|
|
256
|
-
watcher.close();
|
|
257
|
-
}
|
|
258
|
-
});
|
|
259
|
-
let configPath = getConfigPath(context, configOrPath);
|
|
260
|
-
if (configPath !== null) {
|
|
261
|
-
for (let dependency of (0, _getModuleDependencies).default(configPath)){
|
|
262
|
-
if (dependency.file === configPath) {
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
contextConfigDependencies.add(dependency.file);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
if (isNewContext) {
|
|
269
|
-
rebootWatcher(context, configPath, contextConfigDependencies, candidateFiles);
|
|
270
|
-
}
|
|
271
|
-
// Register our temp file as a dependency — we write to this file
|
|
272
|
-
// to trigger rebuilds.
|
|
273
|
-
let touchFile = getTouchFile(context);
|
|
274
|
-
if (touchFile) {
|
|
275
|
-
registerDependency({
|
|
276
|
-
type: 'dependency',
|
|
277
|
-
file: touchFile
|
|
278
|
-
});
|
|
279
|
-
}
|
|
280
|
-
if (tailwindDirectives.size > 0) {
|
|
281
|
-
for (let changedContent of resolvedChangedContent(context, candidateFiles)){
|
|
282
|
-
context.changedContent.push(changedContent);
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
return context;
|
|
286
|
-
};
|
|
287
|
-
};
|
|
288
|
-
}
|
package/nesting/plugin.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
let postcss = require('postcss')
|
|
2
|
-
let postcssNested = require('postcss-nested')
|
|
3
|
-
|
|
4
|
-
module.exports = function nesting(opts = postcssNested) {
|
|
5
|
-
return (root, result) => {
|
|
6
|
-
root.walkAtRules('screen', (rule) => {
|
|
7
|
-
rule.name = 'media'
|
|
8
|
-
rule.params = `screen(${rule.params})`
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
root.walkAtRules('apply', (rule) => {
|
|
12
|
-
rule.before(postcss.decl({ prop: '__apply', value: rule.params, source: rule.source }))
|
|
13
|
-
rule.remove()
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
let plugin = (() => {
|
|
17
|
-
if (typeof opts === 'function') {
|
|
18
|
-
return opts
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (typeof opts === 'string') {
|
|
22
|
-
return require(opts)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (Object.keys(opts).length <= 0) {
|
|
26
|
-
return postcssNested
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
throw new Error('tailwindcss/nesting should be loaded with a nesting plugin.')
|
|
30
|
-
})()
|
|
31
|
-
|
|
32
|
-
postcss([plugin]).process(root, result.opts).sync()
|
|
33
|
-
|
|
34
|
-
root.walkDecls('__apply', (decl) => {
|
|
35
|
-
decl.before(postcss.atRule({ name: 'apply', params: decl.value, source: decl.source }))
|
|
36
|
-
decl.remove()
|
|
37
|
-
})
|
|
38
|
-
|
|
39
|
-
return root
|
|
40
|
-
}
|
|
41
|
-
}
|