tailwindcss 0.0.0-insiders.b7d5a2f → 0.0.0-insiders.b88c8c4

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 (145) hide show
  1. package/README.md +7 -6
  2. package/lib/cli/build/index.js +12 -4
  3. package/lib/cli/build/plugin.js +110 -51
  4. package/lib/cli/build/watching.js +80 -13
  5. package/lib/cli/index.js +222 -10
  6. package/lib/cli/init/index.js +22 -7
  7. package/lib/cli.js +4 -226
  8. package/lib/corePluginList.js +4 -0
  9. package/lib/corePlugins.js +337 -69
  10. package/lib/css/preflight.css +4 -0
  11. package/lib/featureFlags.js +16 -9
  12. package/lib/index.js +4 -46
  13. package/lib/lib/collapseAdjacentRules.js +2 -2
  14. package/lib/lib/collapseDuplicateDeclarations.js +2 -2
  15. package/lib/lib/content.js +21 -11
  16. package/lib/lib/defaultExtractor.js +10 -5
  17. package/lib/lib/detectNesting.js +7 -1
  18. package/lib/lib/evaluateTailwindFunctions.js +4 -4
  19. package/lib/lib/expandApplyAtRules.js +38 -18
  20. package/lib/lib/expandTailwindAtRules.js +35 -10
  21. package/lib/lib/findAtConfigPath.js +7 -7
  22. package/lib/lib/generateRules.js +141 -69
  23. package/lib/lib/getModuleDependencies.js +79 -33
  24. package/lib/lib/load-config.js +36 -0
  25. package/lib/lib/offsets.js +88 -1
  26. package/lib/lib/remap-bitfield.js +87 -0
  27. package/lib/lib/resolveDefaultsAtRules.js +4 -4
  28. package/lib/lib/setupContextUtils.js +277 -77
  29. package/lib/lib/setupTrackingContext.js +29 -8
  30. package/lib/lib/sharedState.js +21 -1
  31. package/lib/oxide/cli/build/deps.js +81 -0
  32. package/lib/oxide/cli/build/index.js +51 -0
  33. package/lib/oxide/cli/build/plugin.js +373 -0
  34. package/lib/oxide/cli/build/utils.js +77 -0
  35. package/lib/oxide/cli/build/watching.js +177 -0
  36. package/lib/oxide/cli/help/index.js +70 -0
  37. package/lib/oxide/cli/index.js +214 -0
  38. package/lib/oxide/cli/init/index.js +50 -0
  39. package/lib/oxide/cli.js +5 -0
  40. package/lib/oxide/postcss-plugin.js +2 -0
  41. package/lib/plugin.js +98 -0
  42. package/lib/postcss-plugins/nesting/plugin.js +2 -2
  43. package/lib/public/colors.js +44 -22
  44. package/lib/public/default-config.js +2 -2
  45. package/lib/public/default-theme.js +2 -2
  46. package/lib/public/load-config.js +10 -0
  47. package/lib/util/applyImportantSelector.js +22 -0
  48. package/lib/util/cloneNodes.js +2 -2
  49. package/lib/util/color.js +20 -6
  50. package/lib/util/createUtilityPlugin.js +2 -2
  51. package/lib/util/dataTypes.js +29 -2
  52. package/lib/util/defaults.js +4 -4
  53. package/lib/util/escapeClassName.js +3 -3
  54. package/lib/util/formatVariantSelector.js +162 -106
  55. package/lib/util/getAllConfigs.js +4 -4
  56. package/lib/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +2 -2
  57. package/lib/util/negateValue.js +2 -2
  58. package/lib/util/normalizeConfig.js +49 -22
  59. package/lib/util/pluginUtils.js +58 -58
  60. package/lib/util/prefixSelector.js +22 -8
  61. package/lib/util/resolveConfig.js +11 -16
  62. package/lib/util/resolveConfigPath.js +19 -7
  63. package/lib/util/splitAtTopLevelOnly.js +7 -1
  64. package/loadConfig.d.ts +4 -0
  65. package/loadConfig.js +2 -0
  66. package/package.json +38 -26
  67. package/peers/index.js +757 -753
  68. package/resolveConfig.d.ts +11 -2
  69. package/scripts/release-channel.js +18 -0
  70. package/scripts/release-notes.js +21 -0
  71. package/scripts/swap-engines.js +40 -0
  72. package/src/cli/build/index.js +13 -9
  73. package/src/cli/build/plugin.js +108 -36
  74. package/src/cli/build/watching.js +108 -13
  75. package/src/cli/index.js +216 -3
  76. package/src/cli/init/index.js +37 -8
  77. package/src/cli.js +4 -220
  78. package/src/corePluginList.js +1 -1
  79. package/src/corePlugins.js +229 -51
  80. package/src/css/preflight.css +4 -0
  81. package/src/featureFlags.js +7 -0
  82. package/src/index.js +4 -46
  83. package/src/lib/content.js +19 -16
  84. package/src/lib/defaultExtractor.js +9 -3
  85. package/src/lib/detectNesting.js +9 -1
  86. package/src/lib/expandApplyAtRules.js +37 -16
  87. package/src/lib/expandTailwindAtRules.js +35 -6
  88. package/src/lib/findAtConfigPath.js +4 -6
  89. package/src/lib/generateRules.js +144 -46
  90. package/src/lib/getModuleDependencies.js +70 -30
  91. package/src/lib/load-config.ts +27 -0
  92. package/src/lib/offsets.js +104 -1
  93. package/src/lib/remap-bitfield.js +82 -0
  94. package/src/lib/setupContextUtils.js +287 -75
  95. package/src/lib/setupTrackingContext.js +35 -10
  96. package/src/lib/sharedState.js +19 -0
  97. package/src/oxide/cli/build/deps.ts +91 -0
  98. package/src/oxide/cli/build/index.ts +47 -0
  99. package/src/oxide/cli/build/plugin.ts +442 -0
  100. package/src/oxide/cli/build/utils.ts +74 -0
  101. package/src/oxide/cli/build/watching.ts +225 -0
  102. package/src/oxide/cli/help/index.ts +69 -0
  103. package/src/oxide/cli/index.ts +204 -0
  104. package/src/oxide/cli/init/index.ts +59 -0
  105. package/src/oxide/cli.ts +1 -0
  106. package/src/oxide/postcss-plugin.ts +1 -0
  107. package/src/plugin.js +107 -0
  108. package/src/public/colors.js +22 -0
  109. package/src/public/default-config.js +1 -1
  110. package/src/public/default-theme.js +2 -2
  111. package/src/public/load-config.js +2 -0
  112. package/src/util/applyImportantSelector.js +19 -0
  113. package/src/util/color.js +17 -2
  114. package/src/util/dataTypes.js +33 -4
  115. package/src/util/formatVariantSelector.js +218 -125
  116. package/src/util/getAllConfigs.js +2 -2
  117. package/src/util/{isValidArbitraryValue.js → isSyntacticallyValidPropertyValue.js} +1 -1
  118. package/src/util/negateValue.js +1 -1
  119. package/src/util/normalizeConfig.js +37 -1
  120. package/src/util/pluginUtils.js +54 -39
  121. package/src/util/prefixSelector.js +28 -10
  122. package/src/util/resolveConfig.js +3 -9
  123. package/src/util/resolveConfigPath.js +12 -1
  124. package/src/util/splitAtTopLevelOnly.js +8 -1
  125. package/stubs/.gitignore +1 -0
  126. package/stubs/.prettierrc.json +6 -0
  127. package/stubs/{defaultConfig.stub.js → config.full.js} +185 -165
  128. package/stubs/{simpleConfig.stub.js → config.simple.js} +0 -1
  129. package/stubs/postcss.config.js +6 -0
  130. package/stubs/tailwind.config.cjs +2 -0
  131. package/stubs/tailwind.config.js +2 -0
  132. package/stubs/tailwind.config.ts +3 -0
  133. package/types/config.d.ts +15 -3
  134. package/types/generated/colors.d.ts +22 -0
  135. package/types/generated/corePluginList.d.ts +1 -1
  136. package/types/generated/default-theme.d.ts +108 -79
  137. package/CHANGELOG.md +0 -2279
  138. package/lib/cli/shared.js +0 -12
  139. package/lib/constants.js +0 -44
  140. package/scripts/calculate-tag-name.js +0 -8
  141. package/scripts/install-integrations.js +0 -27
  142. package/scripts/rebuildFixtures.js +0 -68
  143. package/src/cli/shared.js +0 -5
  144. package/src/constants.js +0 -17
  145. /package/stubs/{defaultPostCssConfig.stub.js → postcss.config.cjs} +0 -0
package/README.md CHANGED
@@ -1,9 +1,10 @@
1
1
  <p align="center">
2
- <a href="https://tailwindcss.com/#gh-light-mode-only" target="_blank">
3
- <img src="./.github/logo-light.svg" alt="Tailwind CSS" width="350" height="70">
4
- </a>
5
- <a href="https://tailwindcss.com/#gh-dark-mode-only" target="_blank">
6
- <img src="./.github/logo-dark.svg" alt="Tailwind CSS" width="350" height="70">
2
+ <a href="https://tailwindcss.com" target="_blank">
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-dark.svg">
5
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg">
6
+ <img alt="Tailwind CSS" src="https://raw.githubusercontent.com/tailwindlabs/tailwindcss/HEAD/.github/logo-light.svg" width="350" height="70" style="max-width: 100%;">
7
+ </picture>
7
8
  </a>
8
9
  </p>
9
10
 
@@ -13,7 +14,7 @@
13
14
 
14
15
 
15
16
  <p align="center">
16
- <a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/workflow/status/tailwindlabs/tailwindcss/Node.js%20CI" alt="Build Status"></a>
17
+ <a href="https://github.com/tailwindlabs/tailwindcss/actions"><img src="https://img.shields.io/github/actions/workflow/status/tailwindlabs/tailwindcss/ci-stable.yml?branch=master" alt="Build Status"></a>
17
18
  <a href="https://www.npmjs.com/package/tailwindcss"><img src="https://img.shields.io/npm/dt/tailwindcss.svg" alt="Total Downloads"></a>
18
19
  <a href="https://github.com/tailwindcss/tailwindcss/releases"><img src="https://img.shields.io/npm/v/tailwindcss.svg" alt="Latest Release"></a>
19
20
  <a href="https://github.com/tailwindcss/tailwindcss/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/tailwindcss.svg" alt="License"></a>
@@ -9,13 +9,14 @@ Object.defineProperty(exports, "build", {
9
9
  });
10
10
  const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs"));
11
11
  const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
12
+ const _resolveConfigPathJs = require("../../util/resolveConfigPath.js");
12
13
  const _pluginJs = require("./plugin.js");
13
14
  function _interopRequireDefault(obj) {
14
15
  return obj && obj.__esModule ? obj : {
15
16
  default: obj
16
17
  };
17
18
  }
18
- async function build(args, configs) {
19
+ async function build(args) {
19
20
  let input = args["--input"];
20
21
  let shouldWatch = args["--watch"];
21
22
  // TODO: Deprecate this in future versions
@@ -32,13 +33,20 @@ async function build(args, configs) {
32
33
  process.exit(9);
33
34
  }
34
35
  // TODO: Reference the @config path here if exists
35
- let configPath = args["--config"] ? args["--config"] : ((defaultPath)=>_fs.default.existsSync(defaultPath) ? defaultPath : null)(_path.default.resolve(`./${configs.tailwind}`));
36
+ let configPath = args["--config"] ? args["--config"] : (0, _resolveConfigPathJs.resolveDefaultConfigPath)();
36
37
  let processor = await (0, _pluginJs.createProcessor)(args, configPath);
37
38
  if (shouldWatch) {
38
- /* Abort the watcher if stdin is closed to avoid zombie processes */ process.stdin.on("end", ()=>process.exit(0));
39
+ // Abort the watcher if stdin is closed to avoid zombie processes
40
+ // You can disable this behavior with --watch=always
41
+ if (args["--watch"] !== "always") {
42
+ process.stdin.on("end", ()=>process.exit(0));
43
+ }
39
44
  process.stdin.resume();
40
45
  await processor.watch();
41
46
  } else {
42
- await processor.build();
47
+ await processor.build().catch((e)=>{
48
+ console.error(e);
49
+ process.exit(1);
50
+ });
43
51
  }
44
52
  }
@@ -18,13 +18,15 @@ const _options = /*#__PURE__*/ _interopRequireDefault(require("postcss-load-conf
18
18
  const _processTailwindFeatures = /*#__PURE__*/ _interopRequireDefault(require("../../processTailwindFeatures"));
19
19
  const _deps = require("./deps");
20
20
  const _utils = require("./utils");
21
- const _shared = require("../shared");
21
+ const _sharedState = require("../../lib/sharedState");
22
22
  const _resolveConfigJs = /*#__PURE__*/ _interopRequireDefault(require("../../../resolveConfig.js"));
23
- const _getModuleDependenciesJs = /*#__PURE__*/ _interopRequireDefault(require("../../lib/getModuleDependencies.js"));
24
23
  const _contentJs = require("../../lib/content.js");
25
24
  const _watchingJs = require("./watching.js");
26
25
  const _fastGlob = /*#__PURE__*/ _interopRequireDefault(require("fast-glob"));
27
26
  const _findAtConfigPathJs = require("../../lib/findAtConfigPath.js");
27
+ const _log = /*#__PURE__*/ _interopRequireDefault(require("../../util/log"));
28
+ const _loadConfig = require("../../lib/load-config");
29
+ const _getModuleDependencies = /*#__PURE__*/ _interopRequireDefault(require("../../lib/getModuleDependencies"));
28
30
  function _interopRequireDefault(obj) {
29
31
  return obj && obj.__esModule ? obj : {
30
32
  default: obj
@@ -108,12 +110,12 @@ let state = {
108
110
  /** @type {any} */ context: null,
109
111
  /** @type {ReturnType<typeof createWatcher> | null} */ watcher: null,
110
112
  /** @type {{content: string, extension: string}[]} */ changedContent: [],
111
- configDependencies: new Set(),
113
+ /** @type {ReturnType<typeof load> | null} */ configBag: null,
112
114
  contextDependencies: new Set(),
113
115
  /** @type {import('../../lib/content.js').ContentPath[]} */ contentPaths: [],
114
116
  refreshContentPaths () {
115
- var ref;
116
- this.contentPaths = (0, _contentJs.parseCandidateFiles)(this.context, (ref = this.context) === null || ref === void 0 ? void 0 : ref.tailwindConfig);
117
+ var _this_context;
118
+ this.contentPaths = (0, _contentJs.parseCandidateFiles)(this.context, (_this_context = this.context) === null || _this_context === void 0 ? void 0 : _this_context.tailwindConfig);
117
119
  },
118
120
  get config () {
119
121
  return this.context.tailwindConfig;
@@ -124,31 +126,38 @@ let state = {
124
126
  dynamic: this.contentPaths.filter((contentPath)=>contentPath.glob !== undefined).map((contentPath)=>contentPath.pattern)
125
127
  };
126
128
  },
127
- loadConfig (configPath) {
129
+ loadConfig (configPath, content) {
128
130
  if (this.watcher && configPath) {
129
- this.refreshConfigDependencies(configPath);
131
+ this.refreshConfigDependencies();
130
132
  }
131
- let config = configPath ? require(configPath) : {};
133
+ let config = (0, _loadConfig.loadConfig)(configPath);
134
+ let dependencies = (0, _getModuleDependencies.default)(configPath);
135
+ this.configBag = {
136
+ config,
137
+ dependencies,
138
+ dispose () {
139
+ for (let file of dependencies){
140
+ delete require.cache[require.resolve(file)];
141
+ }
142
+ }
143
+ };
132
144
  // @ts-ignore
133
- config = (0, _resolveConfigJs.default)(config, {
145
+ this.configBag.config = (0, _resolveConfigJs.default)(this.configBag.config, {
134
146
  content: {
135
147
  files: []
136
148
  }
137
149
  });
138
- return config;
139
- },
140
- refreshConfigDependencies (configPath) {
141
- _shared.env.DEBUG && console.time("Module dependencies");
142
- for (let file of this.configDependencies){
143
- delete require.cache[require.resolve(file)];
144
- }
145
- if (configPath) {
146
- let deps = (0, _getModuleDependenciesJs.default)(configPath).map(({ file })=>file);
147
- for (let dependency of deps){
148
- this.configDependencies.add(dependency);
149
- }
150
+ // Override content files if `--content` has been passed explicitly
151
+ if ((content === null || content === void 0 ? void 0 : content.length) > 0) {
152
+ this.configBag.config.content.files = content;
150
153
  }
151
- _shared.env.DEBUG && console.timeEnd("Module dependencies");
154
+ return this.configBag.config;
155
+ },
156
+ refreshConfigDependencies () {
157
+ var _this_configBag;
158
+ _sharedState.env.DEBUG && console.time("Module dependencies");
159
+ (_this_configBag = this.configBag) === null || _this_configBag === void 0 ? void 0 : _this_configBag.dispose();
160
+ _sharedState.env.DEBUG && console.timeEnd("Module dependencies");
152
161
  },
153
162
  readContentPaths () {
154
163
  let content = [];
@@ -156,69 +165,86 @@ let state = {
156
165
  // TODO: When we make the postcss plugin async-capable this can become async
157
166
  let files = _fastGlob.default.sync(this.contentPatterns.all);
158
167
  for (let file of files){
159
- content.push({
160
- content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"),
161
- extension: _path.default.extname(file).slice(1)
162
- });
168
+ if (_sharedState.env.OXIDE) {
169
+ content.push({
170
+ file,
171
+ extension: _path.default.extname(file).slice(1)
172
+ });
173
+ } else {
174
+ content.push({
175
+ content: _fs.default.readFileSync(_path.default.resolve(file), "utf8"),
176
+ extension: _path.default.extname(file).slice(1)
177
+ });
178
+ }
163
179
  }
164
180
  // Resolve raw content in the tailwind config
165
181
  let rawContent = this.config.content.files.filter((file)=>{
166
182
  return file !== null && typeof file === "object";
167
183
  });
168
- for (let { raw: content1 , extension ="html" } of rawContent){
169
- content1.push({
170
- content: content1,
184
+ for (let { raw: htmlContent , extension ="html" } of rawContent){
185
+ content.push({
186
+ content: htmlContent,
171
187
  extension
172
188
  });
173
189
  }
174
190
  return content;
175
191
  },
176
- getContext ({ createContext , cliConfigPath , root , result }) {
192
+ getContext ({ createContext , cliConfigPath , root , result , content }) {
177
193
  if (this.context) {
178
194
  this.context.changedContent = this.changedContent.splice(0);
179
195
  return this.context;
180
196
  }
181
- _shared.env.DEBUG && console.time("Searching for config");
182
- var ref;
183
- let configPath = (ref = (0, _findAtConfigPathJs.findAtConfigPath)(root, result)) !== null && ref !== void 0 ? ref : cliConfigPath;
184
- _shared.env.DEBUG && console.timeEnd("Searching for config");
185
- _shared.env.DEBUG && console.time("Loading config");
186
- let config = this.loadConfig(configPath);
187
- _shared.env.DEBUG && console.timeEnd("Loading config");
188
- _shared.env.DEBUG && console.time("Creating context");
197
+ _sharedState.env.DEBUG && console.time("Searching for config");
198
+ var _findAtConfigPath;
199
+ let configPath = (_findAtConfigPath = (0, _findAtConfigPathJs.findAtConfigPath)(root, result)) !== null && _findAtConfigPath !== void 0 ? _findAtConfigPath : cliConfigPath;
200
+ _sharedState.env.DEBUG && console.timeEnd("Searching for config");
201
+ _sharedState.env.DEBUG && console.time("Loading config");
202
+ let config = this.loadConfig(configPath, content);
203
+ _sharedState.env.DEBUG && console.timeEnd("Loading config");
204
+ _sharedState.env.DEBUG && console.time("Creating context");
189
205
  this.context = createContext(config, []);
190
206
  Object.assign(this.context, {
191
207
  userConfigPath: configPath
192
208
  });
193
- _shared.env.DEBUG && console.timeEnd("Creating context");
194
- _shared.env.DEBUG && console.time("Resolving content paths");
209
+ _sharedState.env.DEBUG && console.timeEnd("Creating context");
210
+ _sharedState.env.DEBUG && console.time("Resolving content paths");
195
211
  this.refreshContentPaths();
196
- _shared.env.DEBUG && console.timeEnd("Resolving content paths");
212
+ _sharedState.env.DEBUG && console.timeEnd("Resolving content paths");
197
213
  if (this.watcher) {
198
- _shared.env.DEBUG && console.time("Watch new files");
214
+ _sharedState.env.DEBUG && console.time("Watch new files");
199
215
  this.watcher.refreshWatchedFiles();
200
- _shared.env.DEBUG && console.timeEnd("Watch new files");
216
+ _sharedState.env.DEBUG && console.timeEnd("Watch new files");
201
217
  }
202
- _shared.env.DEBUG && console.time("Reading content files");
203
218
  for (let file of this.readContentPaths()){
204
219
  this.context.changedContent.push(file);
205
220
  }
206
- _shared.env.DEBUG && console.timeEnd("Reading content files");
207
221
  return this.context;
208
222
  }
209
223
  };
210
224
  async function createProcessor(args, cliConfigPath) {
225
+ var _args_content;
211
226
  let postcss = (0, _deps.loadPostcss)();
212
227
  let input = args["--input"];
213
228
  let output = args["--output"];
214
229
  let includePostCss = args["--postcss"];
215
230
  let customPostCssPath = typeof args["--postcss"] === "string" ? args["--postcss"] : undefined;
216
231
  let [beforePlugins, afterPlugins, postcssOptions] = includePostCss ? await loadPostCssPlugins(customPostCssPath) : loadBuiltinPostcssPlugins();
232
+ if (args["--purge"]) {
233
+ _log.default.warn("purge-flag-deprecated", [
234
+ "The `--purge` flag has been deprecated.",
235
+ "Please use `--content` instead."
236
+ ]);
237
+ if (!args["--content"]) {
238
+ args["--content"] = args["--purge"];
239
+ }
240
+ }
241
+ var _args_content_split;
242
+ let content = (_args_content_split = (_args_content = args["--content"]) === null || _args_content === void 0 ? void 0 : _args_content.split(/(?<!{[^}]+),/)) !== null && _args_content_split !== void 0 ? _args_content_split : [];
217
243
  let tailwindPlugin = ()=>{
218
244
  return {
219
245
  postcssPlugin: "tailwindcss",
220
246
  Once (root, { result }) {
221
- _shared.env.DEBUG && console.time("Compiling CSS");
247
+ _sharedState.env.DEBUG && console.time("Compiling CSS");
222
248
  (0, _processTailwindFeatures.default)(({ createContext })=>{
223
249
  console.error();
224
250
  console.error("Rebuilding...");
@@ -227,11 +253,12 @@ async function createProcessor(args, cliConfigPath) {
227
253
  createContext,
228
254
  cliConfigPath,
229
255
  root,
230
- result
256
+ result,
257
+ content
231
258
  });
232
259
  };
233
260
  })(root, result);
234
- _shared.env.DEBUG && console.timeEnd("Compiling CSS");
261
+ _sharedState.env.DEBUG && console.timeEnd("Compiling CSS");
235
262
  }
236
263
  };
237
264
  };
@@ -265,18 +292,49 @@ async function createProcessor(args, cliConfigPath) {
265
292
  from: input,
266
293
  to: output
267
294
  })).then((result)=>{
295
+ if (!state.watcher) {
296
+ return result;
297
+ }
298
+ _sharedState.env.DEBUG && console.time("Recording PostCSS dependencies");
299
+ for (let message of result.messages){
300
+ if (message.type === "dependency") {
301
+ state.contextDependencies.add(message.file);
302
+ }
303
+ }
304
+ _sharedState.env.DEBUG && console.timeEnd("Recording PostCSS dependencies");
305
+ // TODO: This needs to be in a different spot
306
+ _sharedState.env.DEBUG && console.time("Watch new files");
307
+ state.watcher.refreshWatchedFiles();
308
+ _sharedState.env.DEBUG && console.timeEnd("Watch new files");
309
+ return result;
310
+ }).then((result)=>{
268
311
  if (!output) {
269
312
  process.stdout.write(result.css);
270
313
  return;
271
314
  }
272
315
  return Promise.all([
273
- (0, _utils.outputFile)(output, result.css),
274
- result.map && (0, _utils.outputFile)(output + ".map", result.map.toString())
316
+ (0, _utils.outputFile)(result.opts.to, result.css),
317
+ result.map && (0, _utils.outputFile)(result.opts.to + ".map", result.map.toString())
275
318
  ]);
276
319
  }).then(()=>{
277
320
  let end = process.hrtime.bigint();
278
321
  console.error();
279
322
  console.error("Done in", (end - start) / BigInt(1e6) + "ms.");
323
+ }).then(()=>{}, (err)=>{
324
+ // TODO: If an initial build fails we can't easily pick up any PostCSS dependencies
325
+ // that were collected before the error occurred
326
+ // The result is not stored on the error so we have to store it externally
327
+ // and pull the messages off of it here somehow
328
+ // This results in a less than ideal DX because the watcher will not pick up
329
+ // changes to imported CSS if one of them caused an error during the initial build
330
+ // If you fix it and then save the main CSS file so there's no error
331
+ // The watcher will start watching the imported CSS files and will be
332
+ // resilient to future errors.
333
+ if (state.watcher) {
334
+ console.error(err);
335
+ } else {
336
+ return Promise.reject(err);
337
+ }
280
338
  });
281
339
  }
282
340
  /**
@@ -299,7 +357,8 @@ async function createProcessor(args, cliConfigPath) {
299
357
  * @param {{file: string, content(): Promise<string>, extension: string}[]} changes
300
358
  */ async rebuild (changes) {
301
359
  let needsNewContext = changes.some((change)=>{
302
- return state.configDependencies.has(change.file) || state.contextDependencies.has(change.file);
360
+ var _state_configBag;
361
+ return ((_state_configBag = state.configBag) === null || _state_configBag === void 0 ? void 0 : _state_configBag.dependencies.has(change.file)) || state.contextDependencies.has(change.file);
303
362
  });
304
363
  if (needsNewContext) {
305
364
  state.context = null;
@@ -37,22 +37,72 @@ function createWatcher(args, { state , rebuild }) {
37
37
  pollInterval: pollInterval
38
38
  } : false
39
39
  });
40
+ // A queue of rebuilds, file reads, etc… to run
40
41
  let chain = Promise.resolve();
41
- let pendingRebuilds = new Set();
42
- let changedContent = [];
42
+ /**
43
+ * A list of files that have been changed since the last rebuild
44
+ *
45
+ * @type {{file: string, content: () => Promise<string>, extension: string}[]}
46
+ */ let changedContent = [];
47
+ /**
48
+ * A list of files for which a rebuild has already been queued.
49
+ * This is used to prevent duplicate rebuilds when multiple events are fired for the same file.
50
+ * The rebuilt file is cleared from this list when it's associated rebuild has _started_
51
+ * This is because if the file is changed during a rebuild it won't trigger a new rebuild which it should
52
+ **/ let pendingRebuilds = new Set();
53
+ let _timer;
54
+ let _reject;
55
+ /**
56
+ * Rebuilds the changed files and resolves when the rebuild is
57
+ * complete regardless of whether it was successful or not
58
+ */ async function rebuildAndContinue() {
59
+ let changes = changedContent.splice(0);
60
+ // There are no changes to rebuild so we can just do nothing
61
+ if (changes.length === 0) {
62
+ return Promise.resolve();
63
+ }
64
+ // Clear all pending rebuilds for the about-to-be-built files
65
+ changes.forEach((change)=>pendingRebuilds.delete(change.file));
66
+ // Resolve the promise even when the rebuild fails
67
+ return rebuild(changes).then(()=>{}, (e)=>{
68
+ console.error(e.toString());
69
+ });
70
+ }
43
71
  /**
44
72
  *
45
73
  * @param {*} file
46
74
  * @param {(() => Promise<string>) | null} content
47
- */ function recordChangedFile(file, content = null) {
75
+ * @param {boolean} skipPendingCheck
76
+ * @returns {Promise<void>}
77
+ */ function recordChangedFile(file, content = null, skipPendingCheck = false) {
48
78
  file = _path.default.resolve(file);
49
- content = content !== null && content !== void 0 ? content : async ()=>await _fs.default.promises.readFile(file, "utf8");
79
+ // Applications like Vim/Neovim fire both rename and change events in succession for atomic writes
80
+ // In that case rebuild has already been queued by rename, so can be skipped in change
81
+ if (pendingRebuilds.has(file) && !skipPendingCheck) {
82
+ return Promise.resolve();
83
+ }
84
+ // Mark that a rebuild of this file is going to happen
85
+ // It MUST happen synchronously before the rebuild is queued for this to be effective
86
+ pendingRebuilds.add(file);
50
87
  changedContent.push({
51
88
  file,
52
- content,
89
+ content: content !== null && content !== void 0 ? content : ()=>_fs.default.promises.readFile(file, "utf8"),
53
90
  extension: _path.default.extname(file).slice(1)
54
91
  });
55
- chain = chain.then(()=>rebuild(changedContent));
92
+ if (_timer) {
93
+ clearTimeout(_timer);
94
+ _reject();
95
+ }
96
+ // If a rebuild is already in progress we don't want to start another one until the 10ms timer has expired
97
+ chain = chain.then(()=>new Promise((resolve, reject)=>{
98
+ _timer = setTimeout(resolve, 10);
99
+ _reject = reject;
100
+ }));
101
+ // Resolves once this file has been rebuilt (or the rebuild for this file has failed)
102
+ // This queues as many rebuilds as there are changed files
103
+ // But those rebuilds happen after some delay
104
+ // And will immediately resolve if there are no changes
105
+ chain = chain.then(rebuildAndContinue, rebuildAndContinue);
56
106
  return chain;
57
107
  }
58
108
  watcher.on("change", (file)=>recordChangedFile(file));
@@ -91,22 +141,39 @@ function createWatcher(args, { state , rebuild }) {
91
141
  if (pendingRebuilds.has(filePath)) {
92
142
  return;
93
143
  }
144
+ // We'll go ahead and add the file to the pending rebuilds list here
145
+ // It'll be removed when the rebuild starts unless the read fails
146
+ // which will be taken care of as well
94
147
  pendingRebuilds.add(filePath);
95
- chain = chain.then(async ()=>{
96
- let content;
148
+ async function enqueue() {
97
149
  try {
98
- content = await (0, _utilsJs.readFileWithRetries)(_path.default.resolve(filePath));
99
- } finally{
100
- pendingRebuilds.delete(filePath);
150
+ // We need to read the file as early as possible outside of the chain
151
+ // because it may be gone by the time we get to it. doing the read
152
+ // immediately increases the chance that the file is still there
153
+ let content = await (0, _utilsJs.readFileWithRetries)(_path.default.resolve(filePath));
154
+ if (content === undefined) {
155
+ return;
156
+ }
157
+ // This will push the rebuild onto the chain
158
+ // We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux
159
+ // This is because the order of events and timing is different on Linux
160
+ // @ts-ignore: TypeScript isn't picking up that content is a string here
161
+ await recordChangedFile(filePath, ()=>content, true);
162
+ } catch {
163
+ // If reading the file fails, it's was probably a deleted temporary file
164
+ // So we can ignore it and no rebuild is needed
101
165
  }
102
- return recordChangedFile(filePath, ()=>content);
166
+ }
167
+ enqueue().then(()=>{
168
+ // If the file read fails we still need to make sure the file isn't stuck in the pending rebuilds list
169
+ pendingRebuilds.delete(filePath);
103
170
  });
104
171
  });
105
172
  return {
106
173
  fswatcher: watcher,
107
174
  refreshWatchedFiles () {
108
175
  watcher.add(Array.from(state.contextDependencies));
109
- watcher.add(Array.from(state.configDependencies));
176
+ watcher.add(Array.from(state.configBag.dependencies));
110
177
  watcher.add(state.contentPatterns.all);
111
178
  }
112
179
  };