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.
Files changed (91) hide show
  1. package/CHANGELOG.md +244 -3
  2. package/LICENSE +1 -2
  3. package/README.md +8 -4
  4. package/colors.js +2 -1
  5. package/defaultConfig.js +2 -1
  6. package/defaultTheme.js +2 -1
  7. package/lib/cli.js +123 -88
  8. package/lib/corePlugins.js +288 -360
  9. package/lib/css/preflight.css +4 -4
  10. package/lib/featureFlags.js +4 -5
  11. package/lib/index.js +12 -3
  12. package/lib/lib/cacheInvalidation.js +69 -0
  13. package/lib/lib/collapseAdjacentRules.js +14 -1
  14. package/lib/lib/collapseDuplicateDeclarations.js +52 -1
  15. package/lib/lib/defaultExtractor.js +44 -0
  16. package/lib/lib/evaluateTailwindFunctions.js +1 -1
  17. package/lib/lib/expandApplyAtRules.js +265 -60
  18. package/lib/lib/expandTailwindAtRules.js +63 -48
  19. package/lib/lib/generateRules.js +136 -34
  20. package/lib/lib/normalizeTailwindDirectives.js +10 -2
  21. package/lib/lib/partitionApplyAtRules.js +53 -0
  22. package/lib/lib/resolveDefaultsAtRules.js +30 -12
  23. package/lib/lib/setupContextUtils.js +137 -81
  24. package/lib/lib/setupTrackingContext.js +8 -7
  25. package/lib/lib/sharedState.js +38 -5
  26. package/{nesting → lib/postcss-plugins/nesting}/README.md +0 -0
  27. package/lib/postcss-plugins/nesting/index.js +17 -0
  28. package/lib/postcss-plugins/nesting/plugin.js +85 -0
  29. package/lib/processTailwindFeatures.js +10 -2
  30. package/lib/util/cloneNodes.js +12 -1
  31. package/lib/util/color.js +23 -8
  32. package/lib/util/createPlugin.js +1 -2
  33. package/lib/util/createUtilityPlugin.js +4 -8
  34. package/lib/util/dataTypes.js +4 -2
  35. package/lib/util/defaults.js +6 -0
  36. package/lib/util/flattenColorPalette.js +1 -3
  37. package/lib/util/log.js +10 -6
  38. package/lib/util/normalizeConfig.js +47 -15
  39. package/lib/util/normalizeScreens.js +6 -5
  40. package/lib/util/parseBoxShadowValue.js +44 -4
  41. package/lib/util/pluginUtils.js +6 -13
  42. package/lib/util/prefixSelector.js +4 -5
  43. package/lib/util/resolveConfig.js +48 -27
  44. package/lib/util/resolveConfigPath.js +1 -2
  45. package/lib/util/toColorValue.js +1 -2
  46. package/lib/util/toPath.js +6 -1
  47. package/lib/util/transformThemeValue.js +4 -8
  48. package/nesting/index.js +2 -12
  49. package/package.json +28 -33
  50. package/peers/index.js +3209 -4239
  51. package/plugin.js +2 -1
  52. package/resolveConfig.js +2 -1
  53. package/src/cli.js +62 -15
  54. package/src/corePlugins.js +212 -217
  55. package/src/css/preflight.css +4 -4
  56. package/src/featureFlags.js +3 -3
  57. package/src/index.js +14 -6
  58. package/src/lib/cacheInvalidation.js +52 -0
  59. package/src/lib/collapseAdjacentRules.js +16 -1
  60. package/src/lib/collapseDuplicateDeclarations.js +66 -1
  61. package/src/lib/defaultExtractor.js +50 -0
  62. package/src/lib/evaluateTailwindFunctions.js +1 -1
  63. package/src/lib/expandApplyAtRules.js +285 -56
  64. package/src/lib/expandTailwindAtRules.js +75 -37
  65. package/src/lib/generateRules.js +121 -27
  66. package/src/lib/normalizeTailwindDirectives.js +7 -1
  67. package/src/lib/partitionApplyAtRules.js +52 -0
  68. package/src/lib/resolveDefaultsAtRules.js +35 -10
  69. package/src/lib/setupContextUtils.js +127 -45
  70. package/src/lib/setupTrackingContext.js +8 -7
  71. package/src/lib/sharedState.js +42 -4
  72. package/src/postcss-plugins/nesting/README.md +42 -0
  73. package/src/postcss-plugins/nesting/index.js +13 -0
  74. package/src/postcss-plugins/nesting/plugin.js +80 -0
  75. package/src/processTailwindFeatures.js +12 -2
  76. package/src/util/cloneNodes.js +14 -1
  77. package/src/util/color.js +20 -7
  78. package/src/util/dataTypes.js +7 -5
  79. package/src/util/defaults.js +6 -0
  80. package/src/util/log.js +10 -6
  81. package/src/util/normalizeConfig.js +24 -3
  82. package/src/util/normalizeScreens.js +6 -3
  83. package/src/util/parseBoxShadowValue.js +51 -3
  84. package/src/util/pluginUtils.js +1 -1
  85. package/src/util/prefixSelector.js +7 -5
  86. package/src/util/resolveConfig.js +41 -1
  87. package/src/util/toPath.js +23 -1
  88. package/stubs/defaultConfig.stub.js +2 -2
  89. package/lib/lib/setupWatchingContext.js +0 -288
  90. package/nesting/plugin.js +0 -41
  91. package/src/lib/setupWatchingContext.js +0 -311
@@ -80,11 +80,13 @@ let lengthUnits = [
80
80
  ]
81
81
  let lengthUnitsPattern = `(?:${lengthUnits.join('|')})`
82
82
  export function length(value) {
83
- return (
84
- value === '0' ||
85
- new RegExp(`${lengthUnitsPattern}$`).test(value) ||
86
- cssFunctions.some((fn) => new RegExp(`^${fn}\\(.+?${lengthUnitsPattern}`).test(value))
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'])
@@ -5,6 +5,12 @@ export function defaults(target, ...sources) {
5
5
  target[k] = source[k]
6
6
  }
7
7
  }
8
+
9
+ for (let k of Object.getOwnPropertySymbols(source)) {
10
+ if (!target?.hasOwnProperty?.(k)) {
11
+ target[k] = source[k]
12
+ }
13
+ }
8
14
  }
9
15
 
10
16
  return target
package/src/util/log.js CHANGED
@@ -1,25 +1,29 @@
1
- import chalk from 'chalk'
1
+ import colors from 'picocolors'
2
2
 
3
3
  let alreadyShown = new Set()
4
4
 
5
- function log(chalk, messages, key) {
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(chalk, '-', message))
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(chalk.bold.cyan('info'), ...(Array.isArray(key) ? [key] : [messages, key]))
21
+ log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key]))
18
22
  },
19
23
  warn(key, messages) {
20
- log(chalk.bold.yellow('warn'), ...(Array.isArray(key) ? [key] : [messages, key]))
24
+ log(colors.bold(colors.yellow('warn')), ...(Array.isArray(key) ? [key] : [messages, key]))
21
25
  },
22
26
  risk(key, messages) {
23
- log(chalk.bold.magenta('risk'), ...(Array.isArray(key) ? [key] : [messages, key]))
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
- // TODO: Add https://tw.wtf/purge-deprecation
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
- // TODO: Add https://tw.wtf/prefix-function
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 = input.split(COMMA)
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 }
@@ -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
- tap(classSelector.value, (baseClass) => {
8
- classSelector.value = `${prefix}${baseClass}`
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
- return val === undefined ? defaultValue : val
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
@@ -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
- return path.split(/[\.\]\[]+/g)
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
- }