From ef056a57d31a14417fa4dc1509bc0e2d30feae29 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 27 Apr 2023 12:21:28 -0400 Subject: [PATCH 01/85] Fix issues with some pseudo-elements (#11111) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix issues with some pseudo-elements We’ve included pseudo elements for backdrop, marker, placeholder, and selection and they were all “jumpable” before we made changes in v3.3.2. Ideally they wouldn’t be because if they ever eventually have any interactivity that could become a problem. * Update changelog --- CHANGELOG.md | 4 +++- src/util/pseudoElements.js | 8 ++++---- tests/format-variant-selector.test.js | 4 ++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd899dc53..0a8b0e891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -- Nothing yet! +### Fixed + +- Fix issue where some pseudo-element variants generated the wrong selector ([#10943](https://github.com/tailwindlabs/tailwindcss/pull/10943), [#10962](https://github.com/tailwindlabs/tailwindcss/pull/10962)) ## [3.3.2] - 2023-04-25 diff --git a/src/util/pseudoElements.js b/src/util/pseudoElements.js index 9f0e54c67..30466ec2c 100644 --- a/src/util/pseudoElements.js +++ b/src/util/pseudoElements.js @@ -26,17 +26,17 @@ /** @type {Record} */ let elementProperties = { '::after': ['terminal', 'jumpable'], - '::backdrop': ['terminal'], + '::backdrop': ['terminal', 'jumpable'], '::before': ['terminal', 'jumpable'], '::cue': ['terminal'], '::cue-region': ['terminal'], '::first-letter': ['terminal', 'jumpable'], '::first-line': ['terminal', 'jumpable'], '::grammar-error': ['terminal'], - '::marker': ['terminal'], + '::marker': ['terminal', 'jumpable'], '::part': ['terminal', 'actionable'], - '::placeholder': ['terminal'], - '::selection': ['terminal'], + '::placeholder': ['terminal', 'jumpable'], + '::selection': ['terminal', 'jumpable'], '::slotted': ['terminal'], '::spelling-error': ['terminal'], '::target-text': ['terminal'], diff --git a/tests/format-variant-selector.test.js b/tests/format-variant-selector.test.js index 0cd0b05ff..9a53f3aac 100644 --- a/tests/format-variant-selector.test.js +++ b/tests/format-variant-selector.test.js @@ -352,6 +352,10 @@ crosscheck(() => { ${'#app :is(:is(.dark &)::before)'} | ${'#app :is(:is(.dark &))::before'} ${'#app :is(.foo::file-selector-button)'} | ${'#app :is(.foo)::file-selector-button'} ${'#app :is(.foo::-webkit-progress-bar)'} | ${'#app :is(.foo)::-webkit-progress-bar'} + ${'.parent::marker li'} | ${'.parent li::marker'} + ${'.parent::selection li'} | ${'.parent li::selection'} + ${'.parent::placeholder input'} | ${'.parent input::placeholder'} + ${'.parent::backdrop dialog'} | ${'.parent dialog::backdrop'} `('should translate "$before" into "$after"', ({ before, after }) => { let result = finalizeSelector('.a', [{ format: before, isArbitraryVariant: false }], { candidate: 'a', From 1f1a6faf2c73d58720a65fece3bbb43997b4f70e Mon Sep 17 00:00:00 2001 From: Dany Castillo <31006608+dcastil@users.noreply.github.com> Date: Fri, 28 Apr 2023 10:06:04 +0200 Subject: [PATCH 02/85] Make font settings propagate into buttons, inputs, etc. (#10940) * Make font settings propagate into buttons, inputs, etc. * update source-maps test due to preflight change * update changelog --------- Co-authored-by: Robin Malfait --- CHANGELOG.md | 1 + src/css/preflight.css | 2 + tests/source-maps.test.js | 424 +++++++++++++++++++------------------- 3 files changed, 216 insertions(+), 211 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a8b0e891..fda241685 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Fix issue where some pseudo-element variants generated the wrong selector ([#10943](https://github.com/tailwindlabs/tailwindcss/pull/10943), [#10962](https://github.com/tailwindlabs/tailwindcss/pull/10962)) +- Make font settings propagate into buttons, inputs, etc. ([#10940](https://github.com/tailwindlabs/tailwindcss/pull/10940)) ## [3.3.2] - 2023-04-25 diff --git a/src/css/preflight.css b/src/css/preflight.css index fab875d95..a53bd8c74 100644 --- a/src/css/preflight.css +++ b/src/css/preflight.css @@ -163,6 +163,8 @@ optgroup, select, textarea { font-family: inherit; /* 1 */ + font-feature-settings: inherit; /* 1 */ + font-variation-settings: inherit; /* 1 */ font-size: 100%; /* 1 */ font-weight: inherit; /* 1 */ line-height: inherit; /* 1 */ diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index dc0092dbc..96f0d04a6 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -179,219 +179,221 @@ crosscheck(({ stable, oxide }) => { '2:20 -> 160:1', '2:6 -> 162:0', '2:6-20 -> 167:2-30', - '2:6-20 -> 168:2-25', - '2:6-20 -> 169:2-30', - '2:6-20 -> 170:2-30', - '2:6-20 -> 171:2-24', - '2:6-20 -> 172:2-19', - '2:6-20 -> 173:2-20', - '2:20 -> 174:0', - '2:6 -> 176:0', - '2:20 -> 178:1', - '2:6 -> 180:0', - '2:6-20 -> 182:2-22', - '2:20 -> 183:0', - '2:6 -> 185:0', - '2:20 -> 188:1', - '2:6 -> 190:0', - '2:6-20 -> 194:2-36', - '2:6-20 -> 195:2-39', - '2:6-20 -> 196:2-32', - '2:20 -> 197:0', - '2:6 -> 199:0', - '2:20 -> 201:1', - '2:6 -> 203:0', - '2:6-20 -> 204:2-15', - '2:20 -> 205:0', - '2:6 -> 207:0', - '2:20 -> 209:1', - '2:6 -> 211:0', - '2:6-20 -> 212:2-18', - '2:20 -> 213:0', - '2:6 -> 215:0', - '2:20 -> 217:1', - '2:6 -> 219:0', - '2:6-20 -> 220:2-26', - '2:20 -> 221:0', - '2:6 -> 223:0', - '2:20 -> 225:1', - '2:6 -> 227:0', - '2:6-20 -> 229:2-14', - '2:20 -> 230:0', - '2:6 -> 232:0', - '2:20 -> 235:1', - '2:6 -> 237:0', - '2:6-20 -> 238:2-39', - '2:6-20 -> 239:2-30', - '2:20 -> 240:0', - '2:6 -> 242:0', - '2:20 -> 244:1', - '2:6 -> 246:0', - '2:6-20 -> 247:2-26', - '2:20 -> 248:0', - '2:6 -> 250:0', - '2:20 -> 253:1', - '2:6 -> 255:0', - '2:6-20 -> 256:2-36', - '2:6-20 -> 257:2-23', - '2:20 -> 258:0', - '2:6 -> 260:0', - '2:20 -> 262:1', - '2:6 -> 264:0', - '2:6-20 -> 265:2-20', - '2:20 -> 266:0', - '2:6 -> 268:0', - '2:20 -> 270:1', - '2:6 -> 272:0', - '2:6-20 -> 285:2-11', - '2:20 -> 286:0', - '2:6 -> 288:0', - '2:6-20 -> 289:2-11', - '2:6-20 -> 290:2-12', - '2:20 -> 291:0', - '2:6 -> 293:0', - '2:6-20 -> 294:2-12', - '2:20 -> 295:0', - '2:6 -> 297:0', - '2:6-20 -> 300:2-18', - '2:6-20 -> 301:2-11', - '2:6-20 -> 302:2-12', - '2:20 -> 303:0', - '2:6 -> 305:0', - '2:20 -> 307:1', - '2:6 -> 309:0', - '2:6-20 -> 310:2-18', - '2:20 -> 311:0', - '2:6 -> 313:0', - '2:20 -> 316:1', - '2:6 -> 318:0', - '2:6-20 -> 320:2-20', - '2:6-20 -> 321:2-24', - '2:20 -> 322:0', - '2:6 -> 324:0', - '2:20 -> 326:1', - '2:6 -> 328:0', - '2:6-20 -> 330:2-17', - '2:20 -> 331:0', - '2:6 -> 333:0', - '2:20 -> 335:1', - '2:6 -> 336:0', - '2:6-20 -> 337:2-17', - '2:20 -> 338:0', - '2:6 -> 340:0', - '2:20 -> 344:1', - '2:6 -> 346:0', - '2:6-20 -> 354:2-24', - '2:6-20 -> 355:2-32', - '2:20 -> 356:0', - '2:6 -> 358:0', - '2:20 -> 360:1', - '2:6 -> 362:0', - '2:6-20 -> 364:2-17', - '2:6-20 -> 365:2-14', - '2:20 -> 366:0', - '2:6-20 -> 368:0-72', - '2:6 -> 369:0', - '2:6-20 -> 370:2-15', - '2:20 -> 371:0', - '2:6 -> 373:0', - '2:6-20 -> 374:2-26', - '2:6-20 -> 375:2-26', - '2:6-20 -> 376:2-21', - '2:6-20 -> 377:2-21', - '2:6-20 -> 378:2-16', - '2:6-20 -> 379:2-16', + '2:6-20 -> 168:2-40', + '2:6-20 -> 169:2-42', + '2:6-20 -> 170:2-25', + '2:6-20 -> 171:2-30', + '2:6-20 -> 172:2-30', + '2:6-20 -> 173:2-24', + '2:6-20 -> 174:2-19', + '2:6-20 -> 175:2-20', + '2:20 -> 176:0', + '2:6 -> 178:0', + '2:20 -> 180:1', + '2:6 -> 182:0', + '2:6-20 -> 184:2-22', + '2:20 -> 185:0', + '2:6 -> 187:0', + '2:20 -> 190:1', + '2:6 -> 192:0', + '2:6-20 -> 196:2-36', + '2:6-20 -> 197:2-39', + '2:6-20 -> 198:2-32', + '2:20 -> 199:0', + '2:6 -> 201:0', + '2:20 -> 203:1', + '2:6 -> 205:0', + '2:6-20 -> 206:2-15', + '2:20 -> 207:0', + '2:6 -> 209:0', + '2:20 -> 211:1', + '2:6 -> 213:0', + '2:6-20 -> 214:2-18', + '2:20 -> 215:0', + '2:6 -> 217:0', + '2:20 -> 219:1', + '2:6 -> 221:0', + '2:6-20 -> 222:2-26', + '2:20 -> 223:0', + '2:6 -> 225:0', + '2:20 -> 227:1', + '2:6 -> 229:0', + '2:6-20 -> 231:2-14', + '2:20 -> 232:0', + '2:6 -> 234:0', + '2:20 -> 237:1', + '2:6 -> 239:0', + '2:6-20 -> 240:2-39', + '2:6-20 -> 241:2-30', + '2:20 -> 242:0', + '2:6 -> 244:0', + '2:20 -> 246:1', + '2:6 -> 248:0', + '2:6-20 -> 249:2-26', + '2:20 -> 250:0', + '2:6 -> 252:0', + '2:20 -> 255:1', + '2:6 -> 257:0', + '2:6-20 -> 258:2-36', + '2:6-20 -> 259:2-23', + '2:20 -> 260:0', + '2:6 -> 262:0', + '2:20 -> 264:1', + '2:6 -> 266:0', + '2:6-20 -> 267:2-20', + '2:20 -> 268:0', + '2:6 -> 270:0', + '2:20 -> 272:1', + '2:6 -> 274:0', + '2:6-20 -> 287:2-11', + '2:20 -> 288:0', + '2:6 -> 290:0', + '2:6-20 -> 291:2-11', + '2:6-20 -> 292:2-12', + '2:20 -> 293:0', + '2:6 -> 295:0', + '2:6-20 -> 296:2-12', + '2:20 -> 297:0', + '2:6 -> 299:0', + '2:6-20 -> 302:2-18', + '2:6-20 -> 303:2-11', + '2:6-20 -> 304:2-12', + '2:20 -> 305:0', + '2:6 -> 307:0', + '2:20 -> 309:1', + '2:6 -> 311:0', + '2:6-20 -> 312:2-18', + '2:20 -> 313:0', + '2:6 -> 315:0', + '2:20 -> 318:1', + '2:6 -> 320:0', + '2:6-20 -> 322:2-20', + '2:6-20 -> 323:2-24', + '2:20 -> 324:0', + '2:6 -> 326:0', + '2:20 -> 328:1', + '2:6 -> 330:0', + '2:6-20 -> 332:2-17', + '2:20 -> 333:0', + '2:6 -> 335:0', + '2:20 -> 337:1', + '2:6 -> 338:0', + '2:6-20 -> 339:2-17', + '2:20 -> 340:0', + '2:6 -> 342:0', + '2:20 -> 346:1', + '2:6 -> 348:0', + '2:6-20 -> 356:2-24', + '2:6-20 -> 357:2-32', + '2:20 -> 358:0', + '2:6 -> 360:0', + '2:20 -> 362:1', + '2:6 -> 364:0', + '2:6-20 -> 366:2-17', + '2:6-20 -> 367:2-14', + '2:20 -> 368:0', + '2:6-20 -> 370:0-72', + '2:6 -> 371:0', + '2:6-20 -> 372:2-15', + '2:20 -> 373:0', + '2:6 -> 375:0', + '2:6-20 -> 376:2-26', + '2:6-20 -> 377:2-26', + '2:6-20 -> 378:2-21', + '2:6-20 -> 379:2-21', '2:6-20 -> 380:2-16', - '2:6-20 -> 381:2-17', - '2:6-20 -> 382:2-17', - '2:6-20 -> 383:2-15', - '2:6-20 -> 384:2-15', - '2:6-20 -> 385:2-20', - '2:6-20 -> 386:2-40', - '2:6-20 -> 387:2-32', - '2:6-20 -> 388:2-31', - '2:6-20 -> 389:2-30', - '2:6-20 -> 390:2-17', - '2:6-20 -> 391:2-22', - '2:6-20 -> 392:2-24', - '2:6-20 -> 393:2-25', - '2:6-20 -> 394:2-26', - '2:6-20 -> 395:2-20', - '2:6-20 -> 396:2-29', - '2:6-20 -> 397:2-30', - '2:6-20 -> 398:2-40', - '2:6-20 -> 399:2-36', - '2:6-20 -> 400:2-29', - '2:6-20 -> 401:2-24', - '2:6-20 -> 402:2-32', - '2:6-20 -> 403:2-14', - '2:6-20 -> 404:2-20', - '2:6-20 -> 405:2-18', - '2:6-20 -> 406:2-19', - '2:6-20 -> 407:2-20', - '2:6-20 -> 408:2-16', - '2:6-20 -> 409:2-18', - '2:6-20 -> 410:2-15', - '2:6-20 -> 411:2-21', - '2:6-20 -> 412:2-23', - '2:6-20 -> 413:2-29', - '2:6-20 -> 414:2-27', - '2:6-20 -> 415:2-28', - '2:6-20 -> 416:2-29', - '2:6-20 -> 417:2-25', - '2:6-20 -> 418:2-26', - '2:6-20 -> 419:2-27', - '2:6 -> 420:2', - '2:20 -> 421:0', - '2:6 -> 423:0', - '2:6-20 -> 424:2-26', - '2:6-20 -> 425:2-26', - '2:6-20 -> 426:2-21', - '2:6-20 -> 427:2-21', - '2:6-20 -> 428:2-16', - '2:6-20 -> 429:2-16', + '2:6-20 -> 381:2-16', + '2:6-20 -> 382:2-16', + '2:6-20 -> 383:2-17', + '2:6-20 -> 384:2-17', + '2:6-20 -> 385:2-15', + '2:6-20 -> 386:2-15', + '2:6-20 -> 387:2-20', + '2:6-20 -> 388:2-40', + '2:6-20 -> 389:2-32', + '2:6-20 -> 390:2-31', + '2:6-20 -> 391:2-30', + '2:6-20 -> 392:2-17', + '2:6-20 -> 393:2-22', + '2:6-20 -> 394:2-24', + '2:6-20 -> 395:2-25', + '2:6-20 -> 396:2-26', + '2:6-20 -> 397:2-20', + '2:6-20 -> 398:2-29', + '2:6-20 -> 399:2-30', + '2:6-20 -> 400:2-40', + '2:6-20 -> 401:2-36', + '2:6-20 -> 402:2-29', + '2:6-20 -> 403:2-24', + '2:6-20 -> 404:2-32', + '2:6-20 -> 405:2-14', + '2:6-20 -> 406:2-20', + '2:6-20 -> 407:2-18', + '2:6-20 -> 408:2-19', + '2:6-20 -> 409:2-20', + '2:6-20 -> 410:2-16', + '2:6-20 -> 411:2-18', + '2:6-20 -> 412:2-15', + '2:6-20 -> 413:2-21', + '2:6-20 -> 414:2-23', + '2:6-20 -> 415:2-29', + '2:6-20 -> 416:2-27', + '2:6-20 -> 417:2-28', + '2:6-20 -> 418:2-29', + '2:6-20 -> 419:2-25', + '2:6-20 -> 420:2-26', + '2:6-20 -> 421:2-27', + '2:6 -> 422:2', + '2:20 -> 423:0', + '2:6 -> 425:0', + '2:6-20 -> 426:2-26', + '2:6-20 -> 427:2-26', + '2:6-20 -> 428:2-21', + '2:6-20 -> 429:2-21', '2:6-20 -> 430:2-16', - '2:6-20 -> 431:2-17', - '2:6-20 -> 432:2-17', - '2:6-20 -> 433:2-15', - '2:6-20 -> 434:2-15', - '2:6-20 -> 435:2-20', - '2:6-20 -> 436:2-40', - '2:6-20 -> 437:2-32', - '2:6-20 -> 438:2-31', - '2:6-20 -> 439:2-30', - '2:6-20 -> 440:2-17', - '2:6-20 -> 441:2-22', - '2:6-20 -> 442:2-24', - '2:6-20 -> 443:2-25', - '2:6-20 -> 444:2-26', - '2:6-20 -> 445:2-20', - '2:6-20 -> 446:2-29', - '2:6-20 -> 447:2-30', - '2:6-20 -> 448:2-40', - '2:6-20 -> 449:2-36', - '2:6-20 -> 450:2-29', - '2:6-20 -> 451:2-24', - '2:6-20 -> 452:2-32', - '2:6-20 -> 453:2-14', - '2:6-20 -> 454:2-20', - '2:6-20 -> 455:2-18', - '2:6-20 -> 456:2-19', - '2:6-20 -> 457:2-20', - '2:6-20 -> 458:2-16', - '2:6-20 -> 459:2-18', - '2:6-20 -> 460:2-15', - '2:6-20 -> 461:2-21', - '2:6-20 -> 462:2-23', - '2:6-20 -> 463:2-29', - '2:6-20 -> 464:2-27', - '2:6-20 -> 465:2-28', - '2:6-20 -> 466:2-29', - '2:6-20 -> 467:2-25', - '2:6-20 -> 468:2-26', - '2:6-20 -> 469:2-27', - '2:6 -> 470:2', - '2:20 -> 471:0', + '2:6-20 -> 431:2-16', + '2:6-20 -> 432:2-16', + '2:6-20 -> 433:2-17', + '2:6-20 -> 434:2-17', + '2:6-20 -> 435:2-15', + '2:6-20 -> 436:2-15', + '2:6-20 -> 437:2-20', + '2:6-20 -> 438:2-40', + '2:6-20 -> 439:2-32', + '2:6-20 -> 440:2-31', + '2:6-20 -> 441:2-30', + '2:6-20 -> 442:2-17', + '2:6-20 -> 443:2-22', + '2:6-20 -> 444:2-24', + '2:6-20 -> 445:2-25', + '2:6-20 -> 446:2-26', + '2:6-20 -> 447:2-20', + '2:6-20 -> 448:2-29', + '2:6-20 -> 449:2-30', + '2:6-20 -> 450:2-40', + '2:6-20 -> 451:2-36', + '2:6-20 -> 452:2-29', + '2:6-20 -> 453:2-24', + '2:6-20 -> 454:2-32', + '2:6-20 -> 455:2-14', + '2:6-20 -> 456:2-20', + '2:6-20 -> 457:2-18', + '2:6-20 -> 458:2-19', + '2:6-20 -> 459:2-20', + '2:6-20 -> 460:2-16', + '2:6-20 -> 461:2-18', + '2:6-20 -> 462:2-15', + '2:6-20 -> 463:2-21', + '2:6-20 -> 464:2-23', + '2:6-20 -> 465:2-29', + '2:6-20 -> 466:2-27', + '2:6-20 -> 467:2-28', + '2:6-20 -> 468:2-29', + '2:6-20 -> 469:2-25', + '2:6-20 -> 470:2-26', + '2:6-20 -> 471:2-27', + '2:6 -> 472:2', + '2:20 -> 473:0', ]) }) From 1f74b14513824be7314579cdaa971e079afe1105 Mon Sep 17 00:00:00 2001 From: Anthony Ricaud Date: Fri, 28 Apr 2023 11:26:13 +0100 Subject: [PATCH 03/85] Add `aria-busy` utility (#10966) * Add aria-busy variant This is useful to show a spinner or dim a region that is updating. Very useful in conjunction with [Turbo](https://turbo.hotwired.dev/reference/attributes#automatically-added-attributes) * update changelog --------- Co-authored-by: Robin Malfait --- CHANGELOG.md | 4 ++++ stubs/config.full.js | 1 + 2 files changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fda241685..41a6fbd3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix issue where some pseudo-element variants generated the wrong selector ([#10943](https://github.com/tailwindlabs/tailwindcss/pull/10943), [#10962](https://github.com/tailwindlabs/tailwindcss/pull/10962)) - Make font settings propagate into buttons, inputs, etc. ([#10940](https://github.com/tailwindlabs/tailwindcss/pull/10940)) +### Added + +- Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) + ## [3.3.2] - 2023-04-25 ### Fixed diff --git a/stubs/config.full.js b/stubs/config.full.js index c32ccd3a0..2dd01c6fd 100644 --- a/stubs/config.full.js +++ b/stubs/config.full.js @@ -15,6 +15,7 @@ module.exports = { bounce: 'bounce 1s infinite', }, aria: { + busy: 'busy="true"', checked: 'checked="true"', disabled: 'disabled="true"', expanded: 'expanded="true"', From 7b3fe8de0f661cbbd52f09fe0e3f592723000c50 Mon Sep 17 00:00:00 2001 From: Eran Hirsch Date: Fri, 28 Apr 2023 19:51:52 +0300 Subject: [PATCH 04/85] Reset dialog element styles (#11069) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * disable useragent styling for dialog * nits * Update src/css/preflight.css * Simplify dialog reset We don’t want to reset everything here. Just the padding should be enough. * Update test --------- Co-authored-by: Robin Malfait Co-authored-by: Jordan Pittman --- src/css/preflight.css | 7 + tests/source-maps.test.js | 261 +++++++++++++++++++------------------- 2 files changed, 140 insertions(+), 128 deletions(-) diff --git a/src/css/preflight.css b/src/css/preflight.css index a53bd8c74..e5e52cd8f 100644 --- a/src/css/preflight.css +++ b/src/css/preflight.css @@ -302,6 +302,13 @@ menu { padding: 0; } +/* +Reset default styling for dialogs. +*/ +dialog { + padding: 0; +} + /* Prevent resizing textareas horizontally by default. */ diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index 96f0d04a6..a19aea687 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -261,139 +261,144 @@ crosscheck(({ stable, oxide }) => { '2:20 -> 305:0', '2:6 -> 307:0', '2:20 -> 309:1', - '2:6 -> 311:0', - '2:6-20 -> 312:2-18', - '2:20 -> 313:0', - '2:6 -> 315:0', - '2:20 -> 318:1', - '2:6 -> 320:0', - '2:6-20 -> 322:2-20', - '2:6-20 -> 323:2-24', - '2:20 -> 324:0', - '2:6 -> 326:0', - '2:20 -> 328:1', - '2:6 -> 330:0', - '2:6-20 -> 332:2-17', - '2:20 -> 333:0', - '2:6 -> 335:0', - '2:20 -> 337:1', - '2:6 -> 338:0', + '2:6 -> 310:0', + '2:6-20 -> 311:2-12', + '2:20 -> 312:0', + '2:6 -> 314:0', + '2:20 -> 316:1', + '2:6 -> 318:0', + '2:6-20 -> 319:2-18', + '2:20 -> 320:0', + '2:6 -> 322:0', + '2:20 -> 325:1', + '2:6 -> 327:0', + '2:6-20 -> 329:2-20', + '2:6-20 -> 330:2-24', + '2:20 -> 331:0', + '2:6 -> 333:0', + '2:20 -> 335:1', + '2:6 -> 337:0', '2:6-20 -> 339:2-17', '2:20 -> 340:0', '2:6 -> 342:0', - '2:20 -> 346:1', - '2:6 -> 348:0', - '2:6-20 -> 356:2-24', - '2:6-20 -> 357:2-32', - '2:20 -> 358:0', - '2:6 -> 360:0', - '2:20 -> 362:1', - '2:6 -> 364:0', - '2:6-20 -> 366:2-17', - '2:6-20 -> 367:2-14', - '2:20 -> 368:0', - '2:6-20 -> 370:0-72', + '2:20 -> 344:1', + '2:6 -> 345:0', + '2:6-20 -> 346:2-17', + '2:20 -> 347:0', + '2:6 -> 349:0', + '2:20 -> 353:1', + '2:6 -> 355:0', + '2:6-20 -> 363:2-24', + '2:6-20 -> 364:2-32', + '2:20 -> 365:0', + '2:6 -> 367:0', + '2:20 -> 369:1', '2:6 -> 371:0', - '2:6-20 -> 372:2-15', - '2:20 -> 373:0', - '2:6 -> 375:0', - '2:6-20 -> 376:2-26', - '2:6-20 -> 377:2-26', - '2:6-20 -> 378:2-21', - '2:6-20 -> 379:2-21', - '2:6-20 -> 380:2-16', - '2:6-20 -> 381:2-16', - '2:6-20 -> 382:2-16', - '2:6-20 -> 383:2-17', - '2:6-20 -> 384:2-17', - '2:6-20 -> 385:2-15', - '2:6-20 -> 386:2-15', - '2:6-20 -> 387:2-20', - '2:6-20 -> 388:2-40', - '2:6-20 -> 389:2-32', - '2:6-20 -> 390:2-31', - '2:6-20 -> 391:2-30', - '2:6-20 -> 392:2-17', - '2:6-20 -> 393:2-22', - '2:6-20 -> 394:2-24', - '2:6-20 -> 395:2-25', - '2:6-20 -> 396:2-26', - '2:6-20 -> 397:2-20', - '2:6-20 -> 398:2-29', - '2:6-20 -> 399:2-30', - '2:6-20 -> 400:2-40', - '2:6-20 -> 401:2-36', - '2:6-20 -> 402:2-29', - '2:6-20 -> 403:2-24', - '2:6-20 -> 404:2-32', - '2:6-20 -> 405:2-14', - '2:6-20 -> 406:2-20', - '2:6-20 -> 407:2-18', - '2:6-20 -> 408:2-19', - '2:6-20 -> 409:2-20', - '2:6-20 -> 410:2-16', - '2:6-20 -> 411:2-18', - '2:6-20 -> 412:2-15', - '2:6-20 -> 413:2-21', - '2:6-20 -> 414:2-23', - '2:6-20 -> 415:2-29', - '2:6-20 -> 416:2-27', - '2:6-20 -> 417:2-28', - '2:6-20 -> 418:2-29', - '2:6-20 -> 419:2-25', - '2:6-20 -> 420:2-26', - '2:6-20 -> 421:2-27', - '2:6 -> 422:2', - '2:20 -> 423:0', - '2:6 -> 425:0', - '2:6-20 -> 426:2-26', + '2:6-20 -> 373:2-17', + '2:6-20 -> 374:2-14', + '2:20 -> 375:0', + '2:6-20 -> 377:0-72', + '2:6 -> 378:0', + '2:6-20 -> 379:2-15', + '2:20 -> 380:0', + '2:6 -> 382:0', + '2:6-20 -> 383:2-26', + '2:6-20 -> 384:2-26', + '2:6-20 -> 385:2-21', + '2:6-20 -> 386:2-21', + '2:6-20 -> 387:2-16', + '2:6-20 -> 388:2-16', + '2:6-20 -> 389:2-16', + '2:6-20 -> 390:2-17', + '2:6-20 -> 391:2-17', + '2:6-20 -> 392:2-15', + '2:6-20 -> 393:2-15', + '2:6-20 -> 394:2-20', + '2:6-20 -> 395:2-40', + '2:6-20 -> 396:2-32', + '2:6-20 -> 397:2-31', + '2:6-20 -> 398:2-30', + '2:6-20 -> 399:2-17', + '2:6-20 -> 400:2-22', + '2:6-20 -> 401:2-24', + '2:6-20 -> 402:2-25', + '2:6-20 -> 403:2-26', + '2:6-20 -> 404:2-20', + '2:6-20 -> 405:2-29', + '2:6-20 -> 406:2-30', + '2:6-20 -> 407:2-40', + '2:6-20 -> 408:2-36', + '2:6-20 -> 409:2-29', + '2:6-20 -> 410:2-24', + '2:6-20 -> 411:2-32', + '2:6-20 -> 412:2-14', + '2:6-20 -> 413:2-20', + '2:6-20 -> 414:2-18', + '2:6-20 -> 415:2-19', + '2:6-20 -> 416:2-20', + '2:6-20 -> 417:2-16', + '2:6-20 -> 418:2-18', + '2:6-20 -> 419:2-15', + '2:6-20 -> 420:2-21', + '2:6-20 -> 421:2-23', + '2:6-20 -> 422:2-29', + '2:6-20 -> 423:2-27', + '2:6-20 -> 424:2-28', + '2:6-20 -> 425:2-29', + '2:6-20 -> 426:2-25', '2:6-20 -> 427:2-26', - '2:6-20 -> 428:2-21', - '2:6-20 -> 429:2-21', - '2:6-20 -> 430:2-16', - '2:6-20 -> 431:2-16', - '2:6-20 -> 432:2-16', - '2:6-20 -> 433:2-17', - '2:6-20 -> 434:2-17', - '2:6-20 -> 435:2-15', - '2:6-20 -> 436:2-15', - '2:6-20 -> 437:2-20', - '2:6-20 -> 438:2-40', - '2:6-20 -> 439:2-32', - '2:6-20 -> 440:2-31', - '2:6-20 -> 441:2-30', - '2:6-20 -> 442:2-17', - '2:6-20 -> 443:2-22', - '2:6-20 -> 444:2-24', - '2:6-20 -> 445:2-25', - '2:6-20 -> 446:2-26', - '2:6-20 -> 447:2-20', - '2:6-20 -> 448:2-29', - '2:6-20 -> 449:2-30', - '2:6-20 -> 450:2-40', - '2:6-20 -> 451:2-36', - '2:6-20 -> 452:2-29', - '2:6-20 -> 453:2-24', - '2:6-20 -> 454:2-32', - '2:6-20 -> 455:2-14', - '2:6-20 -> 456:2-20', - '2:6-20 -> 457:2-18', - '2:6-20 -> 458:2-19', - '2:6-20 -> 459:2-20', - '2:6-20 -> 460:2-16', - '2:6-20 -> 461:2-18', - '2:6-20 -> 462:2-15', - '2:6-20 -> 463:2-21', - '2:6-20 -> 464:2-23', - '2:6-20 -> 465:2-29', - '2:6-20 -> 466:2-27', - '2:6-20 -> 467:2-28', - '2:6-20 -> 468:2-29', - '2:6-20 -> 469:2-25', - '2:6-20 -> 470:2-26', - '2:6-20 -> 471:2-27', - '2:6 -> 472:2', - '2:20 -> 473:0', + '2:6-20 -> 428:2-27', + '2:6 -> 429:2', + '2:20 -> 430:0', + '2:6 -> 432:0', + '2:6-20 -> 433:2-26', + '2:6-20 -> 434:2-26', + '2:6-20 -> 435:2-21', + '2:6-20 -> 436:2-21', + '2:6-20 -> 437:2-16', + '2:6-20 -> 438:2-16', + '2:6-20 -> 439:2-16', + '2:6-20 -> 440:2-17', + '2:6-20 -> 441:2-17', + '2:6-20 -> 442:2-15', + '2:6-20 -> 443:2-15', + '2:6-20 -> 444:2-20', + '2:6-20 -> 445:2-40', + '2:6-20 -> 446:2-32', + '2:6-20 -> 447:2-31', + '2:6-20 -> 448:2-30', + '2:6-20 -> 449:2-17', + '2:6-20 -> 450:2-22', + '2:6-20 -> 451:2-24', + '2:6-20 -> 452:2-25', + '2:6-20 -> 453:2-26', + '2:6-20 -> 454:2-20', + '2:6-20 -> 455:2-29', + '2:6-20 -> 456:2-30', + '2:6-20 -> 457:2-40', + '2:6-20 -> 458:2-36', + '2:6-20 -> 459:2-29', + '2:6-20 -> 460:2-24', + '2:6-20 -> 461:2-32', + '2:6-20 -> 462:2-14', + '2:6-20 -> 463:2-20', + '2:6-20 -> 464:2-18', + '2:6-20 -> 465:2-19', + '2:6-20 -> 466:2-20', + '2:6-20 -> 467:2-16', + '2:6-20 -> 468:2-18', + '2:6-20 -> 469:2-15', + '2:6-20 -> 470:2-21', + '2:6-20 -> 471:2-23', + '2:6-20 -> 472:2-29', + '2:6-20 -> 473:2-27', + '2:6-20 -> 474:2-28', + '2:6-20 -> 475:2-29', + '2:6-20 -> 476:2-25', + '2:6-20 -> 477:2-26', + '2:6-20 -> 478:2-27', + '2:6 -> 479:2', + '2:20 -> 480:0', ]) }) From 9a57badc9f0d4a2b5e6b0922c34ab283aafae3b1 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 28 Apr 2023 12:54:09 -0400 Subject: [PATCH 05/85] Update changelog --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 41a6fbd3d..dddf276c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) +### Changed + +- Reset padding for `` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) + ## [3.3.2] - 2023-04-25 ### Fixed From cdca9cbcfe331b54ca4df80bc720f8cd78e303a0 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Fri, 28 Apr 2023 22:39:08 -0400 Subject: [PATCH 06/85] Update preflight.css --- src/css/preflight.css | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/css/preflight.css b/src/css/preflight.css index e5e52cd8f..4935b607b 100644 --- a/src/css/preflight.css +++ b/src/css/preflight.css @@ -266,7 +266,7 @@ summary { } /* -Removes the default spacing and border for appropriate elements. +Removes the default spacing for appropriate elements. */ blockquote, @@ -302,9 +302,6 @@ menu { padding: 0; } -/* -Reset default styling for dialogs. -*/ dialog { padding: 0; } From 960cb40c6bc906e1e2de4ada124c29a36084a696 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 4 May 2023 10:20:01 -0400 Subject: [PATCH 07/85] Fix parsing of `theme()` inside `calc()` when there are no spaces around operators (#11157) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor * Don’t resolve functions for anything not using theme or screen * Normalize math operators inside calc when handling functions * Inline postcss-value-parser * Treat all functions the same as calc * Remove workaround for calc + operators without spaces * Remove `postcss-value-parser` dependency * Update lockfile * Update sourcemaps * Update changelog * Update `value-parser` formatting * Stop prettier from complaining --- CHANGELOG.md | 1 + package-lock.json | 2 - package-lock.stable.json | 1 - package.json | 1 - package.stable.json | 1 - src/lib/evaluateTailwindFunctions.js | 5 +- src/util/dataTypes.js | 20 +- src/value-parser/LICENSE | 22 ++ src/value-parser/README.md | 3 + src/value-parser/index.d.ts | 177 ++++++++++++++ src/value-parser/index.js | 28 +++ src/value-parser/parse.js | 303 ++++++++++++++++++++++++ src/value-parser/stringify.js | 41 ++++ src/value-parser/unit.js | 118 +++++++++ src/value-parser/walk.js | 18 ++ tests/evaluateTailwindFunctions.test.js | 31 +++ tests/source-maps.test.js | 266 +++++++++++---------- 17 files changed, 893 insertions(+), 145 deletions(-) create mode 100644 src/value-parser/LICENSE create mode 100644 src/value-parser/README.md create mode 100644 src/value-parser/index.d.ts create mode 100644 src/value-parser/index.js create mode 100644 src/value-parser/parse.js create mode 100644 src/value-parser/stringify.js create mode 100644 src/value-parser/unit.js create mode 100644 src/value-parser/walk.js diff --git a/CHANGELOG.md b/CHANGELOG.md index dddf276c8..62b0f5a84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix issue where some pseudo-element variants generated the wrong selector ([#10943](https://github.com/tailwindlabs/tailwindcss/pull/10943), [#10962](https://github.com/tailwindlabs/tailwindcss/pull/10962)) - Make font settings propagate into buttons, inputs, etc. ([#10940](https://github.com/tailwindlabs/tailwindcss/pull/10940)) +- Fix parsing of `theme()` inside `calc()` when there are no spaces around operators ([#11157](https://github.com/tailwindlabs/tailwindcss/pull/11157)) ### Added diff --git a/package-lock.json b/package-lock.json index ecdc2141e..4e61e7b51 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,6 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, @@ -27115,7 +27114,6 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "prettier": "^2.8.8", "resolve": "^1.22.2", "rimraf": "^5.0.0", diff --git a/package-lock.stable.json b/package-lock.stable.json index a80b9c55c..4d422e6a2 100644 --- a/package-lock.stable.json +++ b/package-lock.stable.json @@ -29,7 +29,6 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, diff --git a/package.json b/package.json index e91533f0b..de13cc70b 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,6 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, diff --git a/package.stable.json b/package.stable.json index 308740509..6022310d8 100644 --- a/package.stable.json +++ b/package.stable.json @@ -87,7 +87,6 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0", "resolve": "^1.22.2", "sucrase": "^3.32.0" }, diff --git a/src/lib/evaluateTailwindFunctions.js b/src/lib/evaluateTailwindFunctions.js index 7e04ef428..ff73f466c 100644 --- a/src/lib/evaluateTailwindFunctions.js +++ b/src/lib/evaluateTailwindFunctions.js @@ -1,7 +1,7 @@ import dlv from 'dlv' import didYouMean from 'didyoumean' import transformThemeValue from '../util/transformThemeValue' -import parseValue from 'postcss-value-parser' +import parseValue from '../value-parser/index' import { normalizeScreens } from '../util/normalizeScreens' import buildMediaQuery from '../util/buildMediaQuery' import { toPath } from '../util/toPath' @@ -146,6 +146,9 @@ function resolveVNode(node, vNode, functions) { } function resolveFunctions(node, input, functions) { + let hasAnyFn = Object.keys(functions).some((fn) => input.includes(`${fn}(`)) + if (!hasAnyFn) return input + return parseValue(input) .walk((vNode) => { resolveVNode(node, vNode, functions) diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js index 55cc00579..b4e07c689 100644 --- a/src/util/dataTypes.js +++ b/src/util/dataTypes.js @@ -49,10 +49,22 @@ export function normalize(value, isRoot = true) { value = value.trim() } - // Add spaces around operators inside math functions like calc() that do not follow an operator - // or '('. - value = value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => { + value = normalizeMathOperatorSpacing(value) + + return value +} + +/** + * Add spaces around operators inside math functions + * like calc() that do not follow an operator or '('. + * + * @param {string} value + * @returns {string} + */ +function normalizeMathOperatorSpacing(value) { + return value.replace(/(calc|min|max|clamp)\(.+\)/g, (match) => { let vars = [] + return match .replace(/var\((--.+?)[,)]/g, (match, g1) => { vars.push(g1) @@ -61,8 +73,6 @@ export function normalize(value, isRoot = true) { .replace(/(-?\d*\.?\d(?!\b-\d.+[,)](?![^+\-/*])\D)(?:%|[a-z]+)?|\))([+\-/*])/g, '$1 $2 ') .replace(placeholderRe, () => vars.shift()) }) - - return value } export function url(value) { diff --git a/src/value-parser/LICENSE b/src/value-parser/LICENSE new file mode 100644 index 000000000..6dcaefcbe --- /dev/null +++ b/src/value-parser/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) Bogdan Chadkin + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/value-parser/README.md b/src/value-parser/README.md new file mode 100644 index 000000000..ea9e20291 --- /dev/null +++ b/src/value-parser/README.md @@ -0,0 +1,3 @@ +# postcss-value-parser (forked + inlined) + +This is a customized version of of [PostCSS Value Parser](https://github.com/TrySound/postcss-value-parser) to fix some bugs around parsing CSS functions. diff --git a/src/value-parser/index.d.ts b/src/value-parser/index.d.ts new file mode 100644 index 000000000..0c0c4b991 --- /dev/null +++ b/src/value-parser/index.d.ts @@ -0,0 +1,177 @@ +declare namespace postcssValueParser { + interface BaseNode { + /** + * The offset, inclusive, inside the CSS value at which the node starts. + */ + sourceIndex: number + + /** + * The offset, exclusive, inside the CSS value at which the node ends. + */ + sourceEndIndex: number + + /** + * The node's characteristic value + */ + value: string + } + + interface ClosableNode { + /** + * Whether the parsed CSS value ended before the node was properly closed + */ + unclosed?: true + } + + interface AdjacentAwareNode { + /** + * The token at the start of the node + */ + before: string + + /** + * The token at the end of the node + */ + after: string + } + + interface CommentNode extends BaseNode, ClosableNode { + type: 'comment' + } + + interface DivNode extends BaseNode, AdjacentAwareNode { + type: 'div' + } + + interface FunctionNode extends BaseNode, ClosableNode, AdjacentAwareNode { + type: 'function' + + /** + * Nodes inside the function + */ + nodes: Node[] + } + + interface SpaceNode extends BaseNode { + type: 'space' + } + + interface StringNode extends BaseNode, ClosableNode { + type: 'string' + + /** + * The quote type delimiting the string + */ + quote: '"' | "'" + } + + interface UnicodeRangeNode extends BaseNode { + type: 'unicode-range' + } + + interface WordNode extends BaseNode { + type: 'word' + } + + /** + * Any node parsed from a CSS value + */ + type Node = + | CommentNode + | DivNode + | FunctionNode + | SpaceNode + | StringNode + | UnicodeRangeNode + | WordNode + + interface CustomStringifierCallback { + /** + * @param node The node to stringify + * @returns The serialized CSS representation of the node + */ + (nodes: Node): string | undefined + } + + interface WalkCallback { + /** + * @param node The currently visited node + * @param index The index of the node in the series of parsed nodes + * @param nodes The series of parsed nodes + * @returns Returning `false` will prevent traversal of descendant nodes (only applies if `bubble` was set to `true` in the `walk()` call) + */ + (node: Node, index: number, nodes: Node[]): void | boolean + } + + /** + * A CSS dimension, decomposed into its numeric and unit parts + */ + interface Dimension { + number: string + unit: string + } + + /** + * A wrapper around a parsed CSS value that allows for inspecting and walking nodes + */ + interface ParsedValue { + /** + * The series of parsed nodes + */ + nodes: Node[] + + /** + * Walk all parsed nodes, applying a callback + * + * @param callback A visitor callback that will be executed for each node + * @param bubble When set to `true`, walking will be done inside-out instead of outside-in + */ + walk(callback: WalkCallback, bubble?: boolean): this + } + + interface ValueParser { + /** + * Decompose a CSS dimension into its numeric and unit part + * + * @param value The dimension to decompose + * @returns An object representing `number` and `unit` part of the dimension or `false` if the decomposing fails + */ + unit(value: string): Dimension | false + + /** + * Serialize a series of nodes into a CSS value + * + * @param nodes The nodes to stringify + * @param custom A custom stringifier callback + * @returns The generated CSS value + */ + stringify(nodes: Node | Node[], custom?: CustomStringifierCallback): string + + /** + * Walk a series of nodes, applying a callback + * + * @param nodes The nodes to walk + * @param callback A visitor callback that will be executed for each node + * @param bubble When set to `true`, walking will be done inside-out instead of outside-in + */ + walk(nodes: Node[], callback: WalkCallback, bubble?: boolean): void + + /** + * Parse a CSS value into a series of nodes to operate on + * + * @param value The value to parse + */ + new (value: string): ParsedValue + + /** + * Parse a CSS value into a series of nodes to operate on + * + * @param value The value to parse + */ + (value: string): ParsedValue + } +} + +declare const postcssValueParser: postcssValueParser.ValueParser + +export = postcssValueParser diff --git a/src/value-parser/index.js b/src/value-parser/index.js new file mode 100644 index 000000000..5587ccfa3 --- /dev/null +++ b/src/value-parser/index.js @@ -0,0 +1,28 @@ +var parse = require('./parse') +var walk = require('./walk') +var stringify = require('./stringify') + +function ValueParser(value) { + if (this instanceof ValueParser) { + this.nodes = parse(value) + return this + } + return new ValueParser(value) +} + +ValueParser.prototype.toString = function () { + return Array.isArray(this.nodes) ? stringify(this.nodes) : '' +} + +ValueParser.prototype.walk = function (cb, bubble) { + walk(this.nodes, cb, bubble) + return this +} + +ValueParser.unit = require('./unit') + +ValueParser.walk = walk + +ValueParser.stringify = stringify + +module.exports = ValueParser diff --git a/src/value-parser/parse.js b/src/value-parser/parse.js new file mode 100644 index 000000000..445599664 --- /dev/null +++ b/src/value-parser/parse.js @@ -0,0 +1,303 @@ +var openParentheses = '('.charCodeAt(0) +var closeParentheses = ')'.charCodeAt(0) +var singleQuote = "'".charCodeAt(0) +var doubleQuote = '"'.charCodeAt(0) +var backslash = '\\'.charCodeAt(0) +var slash = '/'.charCodeAt(0) +var comma = ','.charCodeAt(0) +var colon = ':'.charCodeAt(0) +var star = '*'.charCodeAt(0) +var uLower = 'u'.charCodeAt(0) +var uUpper = 'U'.charCodeAt(0) +var plus = '+'.charCodeAt(0) +var isUnicodeRange = /^[a-f0-9?-]+$/i + +module.exports = function (input) { + var tokens = [] + var value = input + + var next, quote, prev, token, escape, escapePos, whitespacePos, parenthesesOpenPos + var pos = 0 + var code = value.charCodeAt(pos) + var max = value.length + var stack = [{ nodes: tokens }] + var balanced = 0 + var parent + + var name = '' + var before = '' + var after = '' + + while (pos < max) { + // Whitespaces + if (code <= 32) { + next = pos + do { + next += 1 + code = value.charCodeAt(next) + } while (code <= 32) + token = value.slice(pos, next) + + prev = tokens[tokens.length - 1] + if (code === closeParentheses && balanced) { + after = token + } else if (prev && prev.type === 'div') { + prev.after = token + prev.sourceEndIndex += token.length + } else if ( + code === comma || + code === colon || + (code === slash && + value.charCodeAt(next + 1) !== star && + (!parent || (parent && parent.type === 'function' && false))) + ) { + before = token + } else { + tokens.push({ + type: 'space', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } + + pos = next + + // Quotes + } else if (code === singleQuote || code === doubleQuote) { + next = pos + quote = code === singleQuote ? "'" : '"' + token = { + type: 'string', + sourceIndex: pos, + quote: quote, + } + do { + escape = false + next = value.indexOf(quote, next + 1) + if (~next) { + escapePos = next + while (value.charCodeAt(escapePos - 1) === backslash) { + escapePos -= 1 + escape = !escape + } + } else { + value += quote + next = value.length - 1 + token.unclosed = true + } + } while (escape) + token.value = value.slice(pos + 1, next) + token.sourceEndIndex = token.unclosed ? next : next + 1 + tokens.push(token) + pos = next + 1 + code = value.charCodeAt(pos) + + // Comments + } else if (code === slash && value.charCodeAt(pos + 1) === star) { + next = value.indexOf('*/', pos) + + token = { + type: 'comment', + sourceIndex: pos, + sourceEndIndex: next + 2, + } + + if (next === -1) { + token.unclosed = true + next = value.length + token.sourceEndIndex = next + } + + token.value = value.slice(pos + 2, next) + tokens.push(token) + + pos = next + 2 + code = value.charCodeAt(pos) + + // Operation within calc + } else if ((code === slash || code === star) && parent && parent.type === 'function' && true) { + token = value[pos] + tokens.push({ + type: 'word', + sourceIndex: pos - before.length, + sourceEndIndex: pos + token.length, + value: token, + }) + pos += 1 + code = value.charCodeAt(pos) + + // Dividers + } else if (code === slash || code === comma || code === colon) { + token = value[pos] + + tokens.push({ + type: 'div', + sourceIndex: pos - before.length, + sourceEndIndex: pos + token.length, + value: token, + before: before, + after: '', + }) + before = '' + + pos += 1 + code = value.charCodeAt(pos) + + // Open parentheses + } else if (openParentheses === code) { + // Whitespaces after open parentheses + next = pos + do { + next += 1 + code = value.charCodeAt(next) + } while (code <= 32) + parenthesesOpenPos = pos + token = { + type: 'function', + sourceIndex: pos - name.length, + value: name, + before: value.slice(parenthesesOpenPos + 1, next), + } + pos = next + + if (name === 'url' && code !== singleQuote && code !== doubleQuote) { + next -= 1 + do { + escape = false + next = value.indexOf(')', next + 1) + if (~next) { + escapePos = next + while (value.charCodeAt(escapePos - 1) === backslash) { + escapePos -= 1 + escape = !escape + } + } else { + value += ')' + next = value.length - 1 + token.unclosed = true + } + } while (escape) + // Whitespaces before closed + whitespacePos = next + do { + whitespacePos -= 1 + code = value.charCodeAt(whitespacePos) + } while (code <= 32) + if (parenthesesOpenPos < whitespacePos) { + if (pos !== whitespacePos + 1) { + token.nodes = [ + { + type: 'word', + sourceIndex: pos, + sourceEndIndex: whitespacePos + 1, + value: value.slice(pos, whitespacePos + 1), + }, + ] + } else { + token.nodes = [] + } + if (token.unclosed && whitespacePos + 1 !== next) { + token.after = '' + token.nodes.push({ + type: 'space', + sourceIndex: whitespacePos + 1, + sourceEndIndex: next, + value: value.slice(whitespacePos + 1, next), + }) + } else { + token.after = value.slice(whitespacePos + 1, next) + token.sourceEndIndex = next + } + } else { + token.after = '' + token.nodes = [] + } + pos = next + 1 + token.sourceEndIndex = token.unclosed ? next : pos + code = value.charCodeAt(pos) + tokens.push(token) + } else { + balanced += 1 + token.after = '' + token.sourceEndIndex = pos + 1 + tokens.push(token) + stack.push(token) + tokens = token.nodes = [] + parent = token + } + name = '' + + // Close parentheses + } else if (closeParentheses === code && balanced) { + pos += 1 + code = value.charCodeAt(pos) + + parent.after = after + parent.sourceEndIndex += after.length + after = '' + balanced -= 1 + stack[stack.length - 1].sourceEndIndex = pos + stack.pop() + parent = stack[balanced] + tokens = parent.nodes + + // Words + } else { + next = pos + do { + if (code === backslash) { + next += 1 + } + next += 1 + code = value.charCodeAt(next) + } while ( + next < max && + !( + code <= 32 || + code === singleQuote || + code === doubleQuote || + code === comma || + code === colon || + code === slash || + code === openParentheses || + (code === star && parent && parent.type === 'function' && true) || + (code === slash && parent.type === 'function' && true) || + (code === closeParentheses && balanced) + ) + ) + token = value.slice(pos, next) + + if (openParentheses === code) { + name = token + } else if ( + (uLower === token.charCodeAt(0) || uUpper === token.charCodeAt(0)) && + plus === token.charCodeAt(1) && + isUnicodeRange.test(token.slice(2)) + ) { + tokens.push({ + type: 'unicode-range', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } else { + tokens.push({ + type: 'word', + sourceIndex: pos, + sourceEndIndex: next, + value: token, + }) + } + + pos = next + } + } + + for (pos = stack.length - 1; pos; pos -= 1) { + stack[pos].unclosed = true + stack[pos].sourceEndIndex = value.length + } + + return stack[0].nodes +} diff --git a/src/value-parser/stringify.js b/src/value-parser/stringify.js new file mode 100644 index 000000000..c95890610 --- /dev/null +++ b/src/value-parser/stringify.js @@ -0,0 +1,41 @@ +function stringifyNode(node, custom) { + var type = node.type + var value = node.value + var buf + var customResult + + if (custom && (customResult = custom(node)) !== undefined) { + return customResult + } else if (type === 'word' || type === 'space') { + return value + } else if (type === 'string') { + buf = node.quote || '' + return buf + value + (node.unclosed ? '' : buf) + } else if (type === 'comment') { + return '/*' + value + (node.unclosed ? '' : '*/') + } else if (type === 'div') { + return (node.before || '') + value + (node.after || '') + } else if (Array.isArray(node.nodes)) { + buf = stringify(node.nodes, custom) + if (type !== 'function') { + return buf + } + return value + '(' + (node.before || '') + buf + (node.after || '') + (node.unclosed ? '' : ')') + } + return value +} + +function stringify(nodes, custom) { + var result, i + + if (Array.isArray(nodes)) { + result = '' + for (i = nodes.length - 1; ~i; i -= 1) { + result = stringifyNode(nodes[i], custom) + result + } + return result + } + return stringifyNode(nodes, custom) +} + +module.exports = stringify diff --git a/src/value-parser/unit.js b/src/value-parser/unit.js new file mode 100644 index 000000000..42d6cd3a7 --- /dev/null +++ b/src/value-parser/unit.js @@ -0,0 +1,118 @@ +var minus = '-'.charCodeAt(0) +var plus = '+'.charCodeAt(0) +var dot = '.'.charCodeAt(0) +var exp = 'e'.charCodeAt(0) +var EXP = 'E'.charCodeAt(0) + +// Check if three code points would start a number +// https://www.w3.org/TR/css-syntax-3/#starts-with-a-number +function likeNumber(value) { + var code = value.charCodeAt(0) + var nextCode + + if (code === plus || code === minus) { + nextCode = value.charCodeAt(1) + + if (nextCode >= 48 && nextCode <= 57) { + return true + } + + var nextNextCode = value.charCodeAt(2) + + if (nextCode === dot && nextNextCode >= 48 && nextNextCode <= 57) { + return true + } + + return false + } + + if (code === dot) { + nextCode = value.charCodeAt(1) + + if (nextCode >= 48 && nextCode <= 57) { + return true + } + + return false + } + + if (code >= 48 && code <= 57) { + return true + } + + return false +} + +// Consume a number +// https://www.w3.org/TR/css-syntax-3/#consume-number +module.exports = function (value) { + var pos = 0 + var length = value.length + var code + var nextCode + var nextNextCode + + if (length === 0 || !likeNumber(value)) { + return false + } + + code = value.charCodeAt(pos) + + if (code === plus || code === minus) { + pos++ + } + + while (pos < length) { + code = value.charCodeAt(pos) + + if (code < 48 || code > 57) { + break + } + + pos += 1 + } + + code = value.charCodeAt(pos) + nextCode = value.charCodeAt(pos + 1) + + if (code === dot && nextCode >= 48 && nextCode <= 57) { + pos += 2 + + while (pos < length) { + code = value.charCodeAt(pos) + + if (code < 48 || code > 57) { + break + } + + pos += 1 + } + } + + code = value.charCodeAt(pos) + nextCode = value.charCodeAt(pos + 1) + nextNextCode = value.charCodeAt(pos + 2) + + if ( + (code === exp || code === EXP) && + ((nextCode >= 48 && nextCode <= 57) || + ((nextCode === plus || nextCode === minus) && nextNextCode >= 48 && nextNextCode <= 57)) + ) { + pos += nextCode === plus || nextCode === minus ? 3 : 2 + + while (pos < length) { + code = value.charCodeAt(pos) + + if (code < 48 || code > 57) { + break + } + + pos += 1 + } + } + + return { + number: value.slice(0, pos), + unit: value.slice(pos), + } +} diff --git a/src/value-parser/walk.js b/src/value-parser/walk.js new file mode 100644 index 000000000..dd20a4392 --- /dev/null +++ b/src/value-parser/walk.js @@ -0,0 +1,18 @@ +module.exports = function walk(nodes, cb, bubble) { + var i, max, node, result + + for (i = 0, max = nodes.length; i < max; i += 1) { + node = nodes[i] + if (!bubble) { + result = cb(node, i, nodes) + } + + if (result !== false && node.type === 'function' && Array.isArray(node.nodes)) { + walk(node.nodes, cb, bubble) + } + + if (bubble) { + cb(node, i, nodes) + } + } +} diff --git a/tests/evaluateTailwindFunctions.test.js b/tests/evaluateTailwindFunctions.test.js index e4085e03e..34eb5adc0 100644 --- a/tests/evaluateTailwindFunctions.test.js +++ b/tests/evaluateTailwindFunctions.test.js @@ -1383,5 +1383,36 @@ crosscheck(({ stable, oxide }) => { // 4. But we've not received any further logs about it expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) }) + + test('it works mayhaps', async () => { + let input = css` + .test { + /* prettier-ignore */ + inset: calc(-1 * (2*theme("spacing.4"))); + /* prettier-ignore */ + padding: calc(-1 * (2* theme("spacing.4"))); + } + ` + + let output = css` + .test { + /* prettier-ignore */ + inset: calc(-1 * (2*1rem)); + /* prettier-ignore */ + padding: calc(-1 * (2* 1rem)); + } + ` + + return run(input, { + theme: { + spacing: { + 4: '1rem', + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) + }) }) }) diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index a19aea687..e0839bf6e 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -260,145 +260,143 @@ crosscheck(({ stable, oxide }) => { '2:6-20 -> 304:2-12', '2:20 -> 305:0', '2:6 -> 307:0', - '2:20 -> 309:1', - '2:6 -> 310:0', - '2:6-20 -> 311:2-12', - '2:20 -> 312:0', - '2:6 -> 314:0', - '2:20 -> 316:1', - '2:6 -> 318:0', - '2:6-20 -> 319:2-18', - '2:20 -> 320:0', - '2:6 -> 322:0', - '2:20 -> 325:1', - '2:6 -> 327:0', - '2:6-20 -> 329:2-20', - '2:6-20 -> 330:2-24', - '2:20 -> 331:0', - '2:6 -> 333:0', - '2:20 -> 335:1', - '2:6 -> 337:0', - '2:6-20 -> 339:2-17', - '2:20 -> 340:0', + '2:6-20 -> 308:2-12', + '2:20 -> 309:0', + '2:6 -> 311:0', + '2:20 -> 313:1', + '2:6 -> 315:0', + '2:6-20 -> 316:2-18', + '2:20 -> 317:0', + '2:6 -> 319:0', + '2:20 -> 322:1', + '2:6 -> 324:0', + '2:6-20 -> 326:2-20', + '2:6-20 -> 327:2-24', + '2:20 -> 328:0', + '2:6 -> 330:0', + '2:20 -> 332:1', + '2:6 -> 334:0', + '2:6-20 -> 336:2-17', + '2:20 -> 337:0', + '2:6 -> 339:0', + '2:20 -> 341:1', '2:6 -> 342:0', - '2:20 -> 344:1', - '2:6 -> 345:0', - '2:6-20 -> 346:2-17', - '2:20 -> 347:0', - '2:6 -> 349:0', - '2:20 -> 353:1', - '2:6 -> 355:0', - '2:6-20 -> 363:2-24', - '2:6-20 -> 364:2-32', - '2:20 -> 365:0', - '2:6 -> 367:0', - '2:20 -> 369:1', - '2:6 -> 371:0', - '2:6-20 -> 373:2-17', - '2:6-20 -> 374:2-14', - '2:20 -> 375:0', - '2:6-20 -> 377:0-72', - '2:6 -> 378:0', - '2:6-20 -> 379:2-15', - '2:20 -> 380:0', - '2:6 -> 382:0', - '2:6-20 -> 383:2-26', - '2:6-20 -> 384:2-26', - '2:6-20 -> 385:2-21', - '2:6-20 -> 386:2-21', - '2:6-20 -> 387:2-16', - '2:6-20 -> 388:2-16', - '2:6-20 -> 389:2-16', - '2:6-20 -> 390:2-17', - '2:6-20 -> 391:2-17', - '2:6-20 -> 392:2-15', - '2:6-20 -> 393:2-15', - '2:6-20 -> 394:2-20', - '2:6-20 -> 395:2-40', - '2:6-20 -> 396:2-32', - '2:6-20 -> 397:2-31', - '2:6-20 -> 398:2-30', - '2:6-20 -> 399:2-17', - '2:6-20 -> 400:2-22', - '2:6-20 -> 401:2-24', - '2:6-20 -> 402:2-25', - '2:6-20 -> 403:2-26', - '2:6-20 -> 404:2-20', - '2:6-20 -> 405:2-29', - '2:6-20 -> 406:2-30', - '2:6-20 -> 407:2-40', - '2:6-20 -> 408:2-36', - '2:6-20 -> 409:2-29', - '2:6-20 -> 410:2-24', - '2:6-20 -> 411:2-32', - '2:6-20 -> 412:2-14', + '2:6-20 -> 343:2-17', + '2:20 -> 344:0', + '2:6 -> 346:0', + '2:20 -> 350:1', + '2:6 -> 352:0', + '2:6-20 -> 360:2-24', + '2:6-20 -> 361:2-32', + '2:20 -> 362:0', + '2:6 -> 364:0', + '2:20 -> 366:1', + '2:6 -> 368:0', + '2:6-20 -> 370:2-17', + '2:6-20 -> 371:2-14', + '2:20 -> 372:0', + '2:6-20 -> 374:0-72', + '2:6 -> 375:0', + '2:6-20 -> 376:2-15', + '2:20 -> 377:0', + '2:6 -> 379:0', + '2:6-20 -> 380:2-26', + '2:6-20 -> 381:2-26', + '2:6-20 -> 382:2-21', + '2:6-20 -> 383:2-21', + '2:6-20 -> 384:2-16', + '2:6-20 -> 385:2-16', + '2:6-20 -> 386:2-16', + '2:6-20 -> 387:2-17', + '2:6-20 -> 388:2-17', + '2:6-20 -> 389:2-15', + '2:6-20 -> 390:2-15', + '2:6-20 -> 391:2-20', + '2:6-20 -> 392:2-40', + '2:6-20 -> 393:2-32', + '2:6-20 -> 394:2-31', + '2:6-20 -> 395:2-30', + '2:6-20 -> 396:2-17', + '2:6-20 -> 397:2-22', + '2:6-20 -> 398:2-24', + '2:6-20 -> 399:2-25', + '2:6-20 -> 400:2-26', + '2:6-20 -> 401:2-20', + '2:6-20 -> 402:2-29', + '2:6-20 -> 403:2-30', + '2:6-20 -> 404:2-40', + '2:6-20 -> 405:2-36', + '2:6-20 -> 406:2-29', + '2:6-20 -> 407:2-24', + '2:6-20 -> 408:2-32', + '2:6-20 -> 409:2-14', + '2:6-20 -> 410:2-20', + '2:6-20 -> 411:2-18', + '2:6-20 -> 412:2-19', '2:6-20 -> 413:2-20', - '2:6-20 -> 414:2-18', - '2:6-20 -> 415:2-19', - '2:6-20 -> 416:2-20', - '2:6-20 -> 417:2-16', - '2:6-20 -> 418:2-18', - '2:6-20 -> 419:2-15', - '2:6-20 -> 420:2-21', - '2:6-20 -> 421:2-23', + '2:6-20 -> 414:2-16', + '2:6-20 -> 415:2-18', + '2:6-20 -> 416:2-15', + '2:6-20 -> 417:2-21', + '2:6-20 -> 418:2-23', + '2:6-20 -> 419:2-29', + '2:6-20 -> 420:2-27', + '2:6-20 -> 421:2-28', '2:6-20 -> 422:2-29', - '2:6-20 -> 423:2-27', - '2:6-20 -> 424:2-28', - '2:6-20 -> 425:2-29', - '2:6-20 -> 426:2-25', - '2:6-20 -> 427:2-26', - '2:6-20 -> 428:2-27', - '2:6 -> 429:2', - '2:20 -> 430:0', - '2:6 -> 432:0', - '2:6-20 -> 433:2-26', - '2:6-20 -> 434:2-26', - '2:6-20 -> 435:2-21', - '2:6-20 -> 436:2-21', - '2:6-20 -> 437:2-16', - '2:6-20 -> 438:2-16', - '2:6-20 -> 439:2-16', - '2:6-20 -> 440:2-17', - '2:6-20 -> 441:2-17', - '2:6-20 -> 442:2-15', - '2:6-20 -> 443:2-15', - '2:6-20 -> 444:2-20', - '2:6-20 -> 445:2-40', - '2:6-20 -> 446:2-32', - '2:6-20 -> 447:2-31', - '2:6-20 -> 448:2-30', - '2:6-20 -> 449:2-17', - '2:6-20 -> 450:2-22', - '2:6-20 -> 451:2-24', - '2:6-20 -> 452:2-25', - '2:6-20 -> 453:2-26', - '2:6-20 -> 454:2-20', - '2:6-20 -> 455:2-29', - '2:6-20 -> 456:2-30', - '2:6-20 -> 457:2-40', - '2:6-20 -> 458:2-36', - '2:6-20 -> 459:2-29', - '2:6-20 -> 460:2-24', - '2:6-20 -> 461:2-32', - '2:6-20 -> 462:2-14', + '2:6-20 -> 423:2-25', + '2:6-20 -> 424:2-26', + '2:6-20 -> 425:2-27', + '2:6 -> 426:2', + '2:20 -> 427:0', + '2:6 -> 429:0', + '2:6-20 -> 430:2-26', + '2:6-20 -> 431:2-26', + '2:6-20 -> 432:2-21', + '2:6-20 -> 433:2-21', + '2:6-20 -> 434:2-16', + '2:6-20 -> 435:2-16', + '2:6-20 -> 436:2-16', + '2:6-20 -> 437:2-17', + '2:6-20 -> 438:2-17', + '2:6-20 -> 439:2-15', + '2:6-20 -> 440:2-15', + '2:6-20 -> 441:2-20', + '2:6-20 -> 442:2-40', + '2:6-20 -> 443:2-32', + '2:6-20 -> 444:2-31', + '2:6-20 -> 445:2-30', + '2:6-20 -> 446:2-17', + '2:6-20 -> 447:2-22', + '2:6-20 -> 448:2-24', + '2:6-20 -> 449:2-25', + '2:6-20 -> 450:2-26', + '2:6-20 -> 451:2-20', + '2:6-20 -> 452:2-29', + '2:6-20 -> 453:2-30', + '2:6-20 -> 454:2-40', + '2:6-20 -> 455:2-36', + '2:6-20 -> 456:2-29', + '2:6-20 -> 457:2-24', + '2:6-20 -> 458:2-32', + '2:6-20 -> 459:2-14', + '2:6-20 -> 460:2-20', + '2:6-20 -> 461:2-18', + '2:6-20 -> 462:2-19', '2:6-20 -> 463:2-20', - '2:6-20 -> 464:2-18', - '2:6-20 -> 465:2-19', - '2:6-20 -> 466:2-20', - '2:6-20 -> 467:2-16', - '2:6-20 -> 468:2-18', - '2:6-20 -> 469:2-15', - '2:6-20 -> 470:2-21', - '2:6-20 -> 471:2-23', + '2:6-20 -> 464:2-16', + '2:6-20 -> 465:2-18', + '2:6-20 -> 466:2-15', + '2:6-20 -> 467:2-21', + '2:6-20 -> 468:2-23', + '2:6-20 -> 469:2-29', + '2:6-20 -> 470:2-27', + '2:6-20 -> 471:2-28', '2:6-20 -> 472:2-29', - '2:6-20 -> 473:2-27', - '2:6-20 -> 474:2-28', - '2:6-20 -> 475:2-29', - '2:6-20 -> 476:2-25', - '2:6-20 -> 477:2-26', - '2:6-20 -> 478:2-27', - '2:6 -> 479:2', - '2:20 -> 480:0', + '2:6-20 -> 473:2-25', + '2:6-20 -> 474:2-26', + '2:6-20 -> 475:2-27', + '2:6 -> 476:2', + '2:20 -> 477:0', ]) }) From 251cc37d7d173c2a0f23430b7a2411c55e81948f Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 8 May 2023 09:32:58 +0200 Subject: [PATCH 08/85] Ensure `repeating-conic-gradient` is detected as an image (#11180) * ensure `repeating-conic-gradient` is detected as an image * update changelog --- CHANGELOG.md | 1 + src/util/dataTypes.js | 3 ++- tests/arbitrary-values.oxide.test.css | 3 +++ tests/arbitrary-values.test.css | 3 +++ tests/arbitrary-values.test.html | 1 + 5 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62b0f5a84..b3024fff6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix issue where some pseudo-element variants generated the wrong selector ([#10943](https://github.com/tailwindlabs/tailwindcss/pull/10943), [#10962](https://github.com/tailwindlabs/tailwindcss/pull/10962)) - Make font settings propagate into buttons, inputs, etc. ([#10940](https://github.com/tailwindlabs/tailwindcss/pull/10940)) - Fix parsing of `theme()` inside `calc()` when there are no spaces around operators ([#11157](https://github.com/tailwindlabs/tailwindcss/pull/11157)) +- Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) ### Added diff --git a/src/util/dataTypes.js b/src/util/dataTypes.js index b4e07c689..2f01aa3d2 100644 --- a/src/util/dataTypes.js +++ b/src/util/dataTypes.js @@ -188,11 +188,12 @@ export function image(value) { } let gradientTypes = new Set([ + 'conic-gradient', 'linear-gradient', 'radial-gradient', + 'repeating-conic-gradient', 'repeating-linear-gradient', 'repeating-radial-gradient', - 'conic-gradient', ]) export function gradient(value) { value = normalize(value) diff --git a/tests/arbitrary-values.oxide.test.css b/tests/arbitrary-values.oxide.test.css index 97d838d7d..214d08601 100644 --- a/tests/arbitrary-values.oxide.test.css +++ b/tests/arbitrary-values.oxide.test.css @@ -652,6 +652,9 @@ .bg-\[linear-gradient\(to_left\,rgb\(var\(--green\)\)\,blue\)\] { background-image: linear-gradient(to left, rgb(var(--green)), blue); } +.bg-\[repeating-conic-gradient\(\#F8F9FA_0\%_25\%\,_white_0\%_50\%\)\] { + background-image: repeating-conic-gradient(#f8f9fa 0% 25%, white 0% 50%); +} .bg-\[url\(\'\/path-to-image\.png\'\)\] { background-image: url('/path-to-image.png'); } diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index dee766991..6f43a5277 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -681,6 +681,9 @@ .bg-\[linear-gradient\(to_left\,rgb\(var\(--green\)\)\,blue\)\] { background-image: linear-gradient(to left, rgb(var(--green)), blue); } +.bg-\[repeating-conic-gradient\(\#F8F9FA_0\%_25\%\,_white_0\%_50\%\)\] { + background-image: repeating-conic-gradient(#f8f9fa 0% 25%, white 0% 50%); +} .bg-\[url\(\'\/path-to-image\.png\'\)\] { background-image: url('/path-to-image.png'); } diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html index 7e65dbf45..5dd6fab84 100644 --- a/tests/arbitrary-values.test.html +++ b/tests/arbitrary-values.test.html @@ -206,6 +206,7 @@
+
From 7dbb59c9db4177b1140c96cc614c5be10eec4404 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Tue, 28 Mar 2023 11:32:00 +0200 Subject: [PATCH 09/85] Revert prepare of v3.3 --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3024fff6..3a6d4ff90 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reset padding for `` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) +### Added + +- [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) + +### Changed + +- [Oxide] Disable color opacity plugins by default in the `oxide` engine ([#10618](https://github.com/tailwindlabs/tailwindcss/pull/10618)) +- [Oxide] Enable relative content paths for the `oxide` engine ([#10621](https://github.com/tailwindlabs/tailwindcss/pull/10621)) + ## [3.3.2] - 2023-04-25 ### Fixed From f8506be2087064bd770d5db661060c94b082aedc Mon Sep 17 00:00:00 2001 From: vjdevra <14150705+vjdevra@users.noreply.github.com> Date: Thu, 13 Apr 2023 16:19:06 +0530 Subject: [PATCH 10/85] Update CODE_OF_CONDUCT.md (#10999) --- .github/CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 7ce9543c5..7dba70ee8 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -2,7 +2,7 @@ The following community guidelines are based on [The Ruby Community Conduct Guidelines](https://www.ruby-lang.org/en/conduct/). -This document provides community guidelines for a respectful, productive, and collaborative place for any person who is willing to contribute to the Tailwind CSS project. It applies to all “collaborative space”, which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.). +This document provides community guidelines for a respectful, productive and collaborative place for any person who is willing to contribute to the Tailwind CSS project. It applies to all “collaborative space”, which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.). - Participants will be tolerant of opposing views. - Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. From 71205d8fcb75e64808e2473b18e84b125317584d Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Fri, 14 Apr 2023 15:11:03 -0400 Subject: [PATCH 11/85] Revert "Update CODE_OF_CONDUCT.md (#10999)" This reverts commit ba5454543e74a6d702ce11b410d27672c2ee4b3f. --- .github/CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 7dba70ee8..7ce9543c5 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -2,7 +2,7 @@ The following community guidelines are based on [The Ruby Community Conduct Guidelines](https://www.ruby-lang.org/en/conduct/). -This document provides community guidelines for a respectful, productive and collaborative place for any person who is willing to contribute to the Tailwind CSS project. It applies to all “collaborative space”, which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.). +This document provides community guidelines for a respectful, productive, and collaborative place for any person who is willing to contribute to the Tailwind CSS project. It applies to all “collaborative space”, which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.). - Participants will be tolerant of opposing views. - Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. From 225a3fa3c63ee3a585e14c30fd3f834c88d630b9 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Fri, 21 Apr 2023 17:55:48 +0000 Subject: [PATCH 12/85] Update resolve to version 1.22.3 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index de13cc70b..f5d2591f1 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,8 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", + "postcss-value-parser": "^4.2.0", + "resolve": "^1.22.3", "sucrase": "^3.32.0" }, "browserslist": [ From 3309d3f635b53a3c7e21a4d58963d32aea689cf2 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 27 Apr 2023 23:34:08 +0200 Subject: [PATCH 13/85] [oxide] Expose experimental Rust parser setup (#11116) * make `sequential` and `parallel` version of a new (tmp) `parse_candidate_strings` * use bitmasks for the strategy Only sending a number over the wire instead of a serialized objects. * use cleaner match syntax --- oxide/crates/core/src/lib.rs | 105 ++++++++++++++++++++++++++++++++--- oxide/crates/node/src/lib.rs | 39 ++++++++++--- 2 files changed, 128 insertions(+), 16 deletions(-) diff --git a/oxide/crates/core/src/lib.rs b/oxide/crates/core/src/lib.rs index 84713e61b..9dd88437d 100644 --- a/oxide/crates/core/src/lib.rs +++ b/oxide/crates/core/src/lib.rs @@ -1,4 +1,5 @@ use crate::parser::Extractor; +use fxhash::FxHashSet; use rayon::prelude::*; use std::path::PathBuf; use tracing::event; @@ -11,14 +12,7 @@ pub mod parser; pub mod utility; pub mod variant; -#[derive(Debug, Clone)] -pub struct ChangedContent { - pub file: Option, - pub content: Option, - pub extension: String, -} - -pub fn parse_candidate_strings_from_files(changed_content: Vec) -> Vec { +fn init_tracing() { if matches!(std::env::var("DEBUG"), Ok(value) if value.eq("*") || value.eq("1") || value.eq("true") || value.contains("tailwind")) { tracing_subscriber::fmt() @@ -27,10 +21,63 @@ pub fn parse_candidate_strings_from_files(changed_content: Vec) .compact() .init(); } +} +#[derive(Debug, Clone)] +pub struct ChangedContent { + pub file: Option, + pub content: Option, + pub extension: String, +} + +#[derive(Debug)] +pub enum IO { + Sequential = 0b0001, + Parallel = 0b0010, +} + +impl From for IO { + fn from(item: u8) -> Self { + match item & 0b0011 { + 0b0001 => IO::Sequential, + 0b0010 => IO::Parallel, + _ => unimplemented!("Unknown 'IO' strategy"), + } + } +} + +#[derive(Debug)] +pub enum Parsing { + Sequential = 0b0100, + Parallel = 0b1000, +} + +impl From for Parsing { + fn from(item: u8) -> Self { + match item & 0b1100 { + 0b0100 => Parsing::Sequential, + 0b1000 => Parsing::Parallel, + _ => unimplemented!("Unknown 'Parsing' strategy"), + } + } +} + +pub fn parse_candidate_strings_from_files(changed_content: Vec) -> Vec { + init_tracing(); parse_all_blobs(read_all_files(changed_content)) } +pub fn parse_candidate_strings(input: Vec, options: u8) -> Vec { + init_tracing(); + + match (IO::from(options), Parsing::from(options)) { + (IO::Sequential, Parsing::Sequential) => parse_all_blobs_sync(read_all_files_sync(input)), + (IO::Sequential, Parsing::Parallel) => parse_all_blobs_sync(read_all_files(input)), + (IO::Parallel, Parsing::Sequential) => parse_all_blobs(read_all_files_sync(input)), + (IO::Parallel, Parsing::Parallel) => parse_all_blobs(read_all_files(input)), + } +} + #[tracing::instrument(skip(changed_content))] fn read_all_files(changed_content: Vec) -> Vec> { event!( @@ -49,6 +96,24 @@ fn read_all_files(changed_content: Vec) -> Vec> { .collect() } +#[tracing::instrument(skip(changed_content))] +fn read_all_files_sync(changed_content: Vec) -> Vec> { + event!( + tracing::Level::INFO, + "Reading {:?} file(s)", + changed_content.len() + ); + + changed_content + .into_iter() + .map(|c| match (c.file, c.content) { + (Some(file), None) => std::fs::read(file).unwrap(), + (None, Some(content)) => content.into_bytes(), + _ => Default::default(), + }) + .collect() +} + #[tracing::instrument(skip(blobs))] fn parse_all_blobs(blobs: Vec>) -> Vec { let input: Vec<_> = blobs.iter().map(|blob| &blob[..]).collect(); @@ -72,3 +137,27 @@ fn parse_all_blobs(blobs: Vec>) -> Vec { result.sort(); result } + +#[tracing::instrument(skip(blobs))] +fn parse_all_blobs_sync(blobs: Vec>) -> Vec { + let input: Vec<_> = blobs.iter().map(|blob| &blob[..]).collect(); + let input = &input[..]; + + let mut result: Vec = input + .iter() + .map(|input| Extractor::unique(input, Default::default())) + .fold(FxHashSet::default(), |mut a, b| { + a.extend(b); + a + }) + .into_iter() + .map(|s| { + // SAFETY: When we parsed the candidates, we already guaranteed that the byte slices + // are valid, therefore we don't have to re-check here when we want to convert it back + // to a string. + unsafe { String::from_utf8_unchecked(s.to_vec()) } + }) + .collect(); + result.sort(); + result +} diff --git a/oxide/crates/node/src/lib.rs b/oxide/crates/node/src/lib.rs index 20961adcb..f8b927db5 100644 --- a/oxide/crates/node/src/lib.rs +++ b/oxide/crates/node/src/lib.rs @@ -1,3 +1,4 @@ +use napi::bindgen_prelude::ToNapiValue; use std::path::PathBuf; #[macro_use] @@ -11,16 +12,38 @@ pub struct ChangedContent { pub extension: String, } +impl From for tailwindcss_core::ChangedContent { + fn from(changed_content: ChangedContent) -> Self { + tailwindcss_core::ChangedContent { + file: changed_content.file.map(PathBuf::from), + content: changed_content.content, + extension: changed_content.extension, + } + } +} + #[napi] pub fn parse_candidate_strings_from_files(changed_content: Vec) -> Vec { tailwindcss_core::parse_candidate_strings_from_files( - changed_content - .into_iter() - .map(|changed_content| tailwindcss_core::ChangedContent { - file: changed_content.file.map(PathBuf::from), - content: changed_content.content, - extension: changed_content.extension, - }) - .collect(), + changed_content.into_iter().map(Into::into).collect(), ) } + +#[derive(Debug)] +#[napi] +pub enum IO { + Sequential = 0b0001, + Parallel = 0b0010, +} + +#[derive(Debug)] +#[napi] +pub enum Parsing { + Sequential = 0b0100, + Parallel = 0b1000, +} + +#[napi] +pub fn parse_candidate_strings(input: Vec, strategy: u8) -> Vec { + tailwindcss_core::parse_candidate_strings(input.into_iter().map(Into::into).collect(), strategy) +} From a4314c052bfbecdad6e15edd437d49d668cb5aaa Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 27 Apr 2023 23:45:10 +0200 Subject: [PATCH 14/85] use older version of centos/nodejs-12 --- .github/workflows/release-insiders-oxide.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-insiders-oxide.yml b/.github/workflows/release-insiders-oxide.yml index 4130349ba..e074d064d 100644 --- a/.github/workflows/release-insiders-oxide.yml +++ b/.github/workflows/release-insiders-oxide.yml @@ -170,7 +170,7 @@ jobs: include: - target: x86_64-unknown-linux-gnu strip: strip - image: docker.io/centos/nodejs-14-centos7 + image: docker.io/centos/nodejs-12-centos7 - target: aarch64-unknown-linux-gnu strip: aarch64-linux-gnu-strip image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian From 9799e8824402595a66bf039f8096ed593bb76203 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 12:55:43 +0000 Subject: [PATCH 15/85] Update @swc/core to version 1.3.56 --- package-lock.json | 292 +++++++++++++++++++++++----------------------- package.json | 2 +- 2 files changed, 148 insertions(+), 146 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4e61e7b51..df4523ed5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,7 +36,8 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", + "postcss-value-parser": "^4.2.0", + "resolve": "^1.22.3", "sucrase": "^3.32.0" }, "bin": { @@ -45,7 +46,7 @@ }, "devDependencies": { "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", + "@swc/core": "^1.3.56", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "autoprefixer": "^10.4.14", @@ -3939,9 +3940,9 @@ } }, "node_modules/@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.57.tgz", + "integrity": "sha512-gAT80hOVeK5qoi+BRlgXWgJYI9cbQn2oi05A09Tvb6vjFgBsr9SlQGNZB9uMlcXRXspkZFf9l3yyWRtT4we3Yw==", "dev": true, "hasInstallScript": true, "engines": { @@ -3952,16 +3953,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" + "@swc/core-darwin-arm64": "1.3.57", + "@swc/core-darwin-x64": "1.3.57", + "@swc/core-linux-arm-gnueabihf": "1.3.57", + "@swc/core-linux-arm64-gnu": "1.3.57", + "@swc/core-linux-arm64-musl": "1.3.57", + "@swc/core-linux-x64-gnu": "1.3.57", + "@swc/core-linux-x64-musl": "1.3.57", + "@swc/core-win32-arm64-msvc": "1.3.57", + "@swc/core-win32-ia32-msvc": "1.3.57", + "@swc/core-win32-x64-msvc": "1.3.57" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -3973,9 +3974,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.57.tgz", + "integrity": "sha512-lhAK9kF/ppZdNTdaxJl2gE0bXubzQXTgxB2Xojme/1sbOipaLTskBbJ3FLySChpmVOzD0QSCTiW8w/dmQxqNIQ==", "cpu": [ "arm64" ], @@ -3989,9 +3990,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.57.tgz", + "integrity": "sha512-jsTDH8Et/xdOM/ZCNvtrT6J8FT255OrMhEDvHZQZTgoky4oW/3FHUfji4J2FE97gitJqNJI8MuNuiGq81pIJRw==", "cpu": [ "x64" ], @@ -4005,9 +4006,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.57.tgz", + "integrity": "sha512-MZv3fwcCmppbwfCWaE8cZvzbXOjX7n5SEC1hF2lgItTqp4S04dFk1iX50jKr6xS6xSLlRBPqDxwZH0sBpHaEuA==", "cpu": [ "arm" ], @@ -4021,9 +4022,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.57.tgz", + "integrity": "sha512-wUeqa/qbkOEGl6TaDQZZL7txrQXs1vL7ERjPYhi9El+ywacFY/rTW2pK5DqaNk2eulVnLhbbNjsE1OMGSEWGkQ==", "cpu": [ "arm64" ], @@ -4037,9 +4038,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.57.tgz", + "integrity": "sha512-pZfp1B9XfH7ZhDKFjr4qbyM093zU2Ri0IZq2M2A4W9q92+Ivy8oEIqw+gSRO3jwMDqRMEtFD49YuFhkJQakxdA==", "cpu": [ "arm64" ], @@ -4053,9 +4054,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.57.tgz", + "integrity": "sha512-dvtQnv07NikV+CJ+9PYJ3fqphSigzfvSUH6wRCmb5OzLDDLFnPLMrEO0pGeURvdIWCOhngcHF252C1Hl5uFSzA==", "cpu": [ "x64" ], @@ -4069,9 +4070,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.57.tgz", + "integrity": "sha512-1TKCSngyQxpzwBYDzF5MrEfYRDhlzt/GN1ZqlSnsJIPGkABOWZxYDvWJuMrkASdIztn3jSTPU2ih7rR7YQ8IIw==", "cpu": [ "x64" ], @@ -4085,9 +4086,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.57.tgz", + "integrity": "sha512-HvBYFyf4uBua/jyTrcFLKcq8SIbKVYfz2qWsbgSAZvuQPZvDC1XhN5EDH2tPZmT97F0CJx3fltH5nli6XY1/EQ==", "cpu": [ "arm64" ], @@ -4101,9 +4102,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.57.tgz", + "integrity": "sha512-PS8AtK9e6Rp97S0ek9W5VCZNCbDaHBUasiJUmaYqRVCq/Mn6S7eQlhd0iUDnjsagigQtoCRgMUzkVknd1tarsQ==", "cpu": [ "ia32" ], @@ -4117,9 +4118,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.57.tgz", + "integrity": "sha512-A6aX/Rpp0v3g7Spf3LSwR+ivviH8x+1xla612KLZmlc0yymWt9BMd3CmBkzyRBr2e41zGCrkf6tra6wgtCbAwA==", "cpu": [ "x64" ], @@ -13101,11 +13102,11 @@ } }, "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "dependencies": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -18758,90 +18759,90 @@ } }, "@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.57.tgz", + "integrity": "sha512-gAT80hOVeK5qoi+BRlgXWgJYI9cbQn2oi05A09Tvb6vjFgBsr9SlQGNZB9uMlcXRXspkZFf9l3yyWRtT4we3Yw==", "dev": true, "requires": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" + "@swc/core-darwin-arm64": "1.3.57", + "@swc/core-darwin-x64": "1.3.57", + "@swc/core-linux-arm-gnueabihf": "1.3.57", + "@swc/core-linux-arm64-gnu": "1.3.57", + "@swc/core-linux-arm64-musl": "1.3.57", + "@swc/core-linux-x64-gnu": "1.3.57", + "@swc/core-linux-x64-musl": "1.3.57", + "@swc/core-win32-arm64-msvc": "1.3.57", + "@swc/core-win32-ia32-msvc": "1.3.57", + "@swc/core-win32-x64-msvc": "1.3.57" } }, "@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.57.tgz", + "integrity": "sha512-lhAK9kF/ppZdNTdaxJl2gE0bXubzQXTgxB2Xojme/1sbOipaLTskBbJ3FLySChpmVOzD0QSCTiW8w/dmQxqNIQ==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.57.tgz", + "integrity": "sha512-jsTDH8Et/xdOM/ZCNvtrT6J8FT255OrMhEDvHZQZTgoky4oW/3FHUfji4J2FE97gitJqNJI8MuNuiGq81pIJRw==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.57.tgz", + "integrity": "sha512-MZv3fwcCmppbwfCWaE8cZvzbXOjX7n5SEC1hF2lgItTqp4S04dFk1iX50jKr6xS6xSLlRBPqDxwZH0sBpHaEuA==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.57.tgz", + "integrity": "sha512-wUeqa/qbkOEGl6TaDQZZL7txrQXs1vL7ERjPYhi9El+ywacFY/rTW2pK5DqaNk2eulVnLhbbNjsE1OMGSEWGkQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.57.tgz", + "integrity": "sha512-pZfp1B9XfH7ZhDKFjr4qbyM093zU2Ri0IZq2M2A4W9q92+Ivy8oEIqw+gSRO3jwMDqRMEtFD49YuFhkJQakxdA==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.57.tgz", + "integrity": "sha512-dvtQnv07NikV+CJ+9PYJ3fqphSigzfvSUH6wRCmb5OzLDDLFnPLMrEO0pGeURvdIWCOhngcHF252C1Hl5uFSzA==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.57.tgz", + "integrity": "sha512-1TKCSngyQxpzwBYDzF5MrEfYRDhlzt/GN1ZqlSnsJIPGkABOWZxYDvWJuMrkASdIztn3jSTPU2ih7rR7YQ8IIw==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.57.tgz", + "integrity": "sha512-HvBYFyf4uBua/jyTrcFLKcq8SIbKVYfz2qWsbgSAZvuQPZvDC1XhN5EDH2tPZmT97F0CJx3fltH5nli6XY1/EQ==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.57.tgz", + "integrity": "sha512-PS8AtK9e6Rp97S0ek9W5VCZNCbDaHBUasiJUmaYqRVCq/Mn6S7eQlhd0iUDnjsagigQtoCRgMUzkVknd1tarsQ==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.57.tgz", + "integrity": "sha512-A6aX/Rpp0v3g7Spf3LSwR+ivviH8x+1xla612KLZmlc0yymWt9BMd3CmBkzyRBr2e41zGCrkf6tra6wgtCbAwA==", "dev": true, "optional": true }, @@ -25810,11 +25811,11 @@ "dev": true }, "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "requires": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } @@ -27071,7 +27072,7 @@ "requires": { "@alloc/quick-lru": "^5.2.0", "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", + "@swc/core": "^1.3.56", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "@tailwindcss/integrations-content-resolution": "file:integrations/content-resolution", @@ -27114,8 +27115,9 @@ "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0", "prettier": "^2.8.8", - "resolve": "^1.22.2", + "resolve": "^1.22.3", "rimraf": "^5.0.0", "source-map-js": "^1.0.2", "sucrase": "^3.32.0", @@ -29407,90 +29409,90 @@ } }, "@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.57.tgz", + "integrity": "sha512-gAT80hOVeK5qoi+BRlgXWgJYI9cbQn2oi05A09Tvb6vjFgBsr9SlQGNZB9uMlcXRXspkZFf9l3yyWRtT4we3Yw==", "dev": true, "requires": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" + "@swc/core-darwin-arm64": "1.3.57", + "@swc/core-darwin-x64": "1.3.57", + "@swc/core-linux-arm-gnueabihf": "1.3.57", + "@swc/core-linux-arm64-gnu": "1.3.57", + "@swc/core-linux-arm64-musl": "1.3.57", + "@swc/core-linux-x64-gnu": "1.3.57", + "@swc/core-linux-x64-musl": "1.3.57", + "@swc/core-win32-arm64-msvc": "1.3.57", + "@swc/core-win32-ia32-msvc": "1.3.57", + "@swc/core-win32-x64-msvc": "1.3.57" } }, "@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.57.tgz", + "integrity": "sha512-lhAK9kF/ppZdNTdaxJl2gE0bXubzQXTgxB2Xojme/1sbOipaLTskBbJ3FLySChpmVOzD0QSCTiW8w/dmQxqNIQ==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.57.tgz", + "integrity": "sha512-jsTDH8Et/xdOM/ZCNvtrT6J8FT255OrMhEDvHZQZTgoky4oW/3FHUfji4J2FE97gitJqNJI8MuNuiGq81pIJRw==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.57.tgz", + "integrity": "sha512-MZv3fwcCmppbwfCWaE8cZvzbXOjX7n5SEC1hF2lgItTqp4S04dFk1iX50jKr6xS6xSLlRBPqDxwZH0sBpHaEuA==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.57.tgz", + "integrity": "sha512-wUeqa/qbkOEGl6TaDQZZL7txrQXs1vL7ERjPYhi9El+ywacFY/rTW2pK5DqaNk2eulVnLhbbNjsE1OMGSEWGkQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.57.tgz", + "integrity": "sha512-pZfp1B9XfH7ZhDKFjr4qbyM093zU2Ri0IZq2M2A4W9q92+Ivy8oEIqw+gSRO3jwMDqRMEtFD49YuFhkJQakxdA==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.57.tgz", + "integrity": "sha512-dvtQnv07NikV+CJ+9PYJ3fqphSigzfvSUH6wRCmb5OzLDDLFnPLMrEO0pGeURvdIWCOhngcHF252C1Hl5uFSzA==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.57.tgz", + "integrity": "sha512-1TKCSngyQxpzwBYDzF5MrEfYRDhlzt/GN1ZqlSnsJIPGkABOWZxYDvWJuMrkASdIztn3jSTPU2ih7rR7YQ8IIw==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.57.tgz", + "integrity": "sha512-HvBYFyf4uBua/jyTrcFLKcq8SIbKVYfz2qWsbgSAZvuQPZvDC1XhN5EDH2tPZmT97F0CJx3fltH5nli6XY1/EQ==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.57.tgz", + "integrity": "sha512-PS8AtK9e6Rp97S0ek9W5VCZNCbDaHBUasiJUmaYqRVCq/Mn6S7eQlhd0iUDnjsagigQtoCRgMUzkVknd1tarsQ==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", + "version": "1.3.57", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.57.tgz", + "integrity": "sha512-A6aX/Rpp0v3g7Spf3LSwR+ivviH8x+1xla612KLZmlc0yymWt9BMd3CmBkzyRBr2e41zGCrkf6tra6wgtCbAwA==", "dev": true, "optional": true }, @@ -36459,11 +36461,11 @@ "dev": true }, "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.3.tgz", + "integrity": "sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==", "requires": { - "is-core-module": "^2.11.0", + "is-core-module": "^2.12.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" } diff --git a/package.json b/package.json index f5d2591f1..2a68dd423 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ ], "devDependencies": { "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", + "@swc/core": "^1.3.56", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "autoprefixer": "^10.4.14", From 9b6047d6398e229b65d05757f8f3d2c64f981fed Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Wed, 3 May 2023 15:56:11 +0000 Subject: [PATCH 16/85] Update vite to version 4.3.4 --- integrations/vite/package.json | 2 +- package-lock.json | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/integrations/vite/package.json b/integrations/vite/package.json index 4b9649cab..8a76f10fe 100644 --- a/integrations/vite/package.json +++ b/integrations/vite/package.json @@ -21,6 +21,6 @@ }, "devDependencies": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.4" } } diff --git a/package-lock.json b/package-lock.json index df4523ed5..e5d9a7405 100644 --- a/package-lock.json +++ b/package-lock.json @@ -119,7 +119,7 @@ "version": "0.0.0", "devDependencies": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.4" } }, "integrations/webpack-4": { @@ -15619,13 +15619,13 @@ "dev": true }, "node_modules/vite": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.2.tgz", - "integrity": "sha512-9R53Mf+TBoXCYejcL+qFbZde+eZveQLDYd9XgULILLC1a5ZwPaqgmdVpL8/uvw2BM/1TzetWjglwm+3RO+xTyw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz", + "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==", "dev": true, "dependencies": { "esbuild": "^0.17.5", - "postcss": "^8.4.21", + "postcss": "^8.4.23", "rollup": "^3.21.0" }, "bin": { @@ -18932,7 +18932,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.4" } }, "@tailwindcss/integrations-webpack-4": { @@ -29582,7 +29582,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.2" + "vite": "^4.3.4" } }, "@tailwindcss/integrations-webpack-4": { @@ -38282,14 +38282,14 @@ } }, "vite": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.2.tgz", - "integrity": "sha512-9R53Mf+TBoXCYejcL+qFbZde+eZveQLDYd9XgULILLC1a5ZwPaqgmdVpL8/uvw2BM/1TzetWjglwm+3RO+xTyw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz", + "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==", "dev": true, "requires": { "esbuild": "^0.17.5", "fsevents": "~2.3.2", - "postcss": "^8.4.21", + "postcss": "^8.4.23", "rollup": "^3.21.0" } }, @@ -39478,14 +39478,14 @@ } }, "vite": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.2.tgz", - "integrity": "sha512-9R53Mf+TBoXCYejcL+qFbZde+eZveQLDYd9XgULILLC1a5ZwPaqgmdVpL8/uvw2BM/1TzetWjglwm+3RO+xTyw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz", + "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==", "dev": true, "requires": { "esbuild": "^0.17.5", "fsevents": "~2.3.2", - "postcss": "^8.4.21", + "postcss": "^8.4.23", "rollup": "^3.21.0" } }, From 3e015818d6fc7c083c51b99214aa3a7238559dc4 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Sat, 6 May 2023 13:56:05 +0000 Subject: [PATCH 17/85] Update postcss-selector-parser to version 6.0.12 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2a68dd423..476615caf 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,7 @@ "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.12", "postcss-value-parser": "^4.2.0", "resolve": "^1.22.3", "sucrase": "^3.32.0" From 8af8e0d1e6a119896b9158de16e6a1905c7b5515 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Sun, 7 May 2023 09:41:05 +0000 Subject: [PATCH 18/85] Update cssnano to version 6.0.1 --- package-lock.json | 17 +++++++++++------ package.json | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index e5d9a7405..5d978794c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.12", "postcss-value-parser": "^4.2.0", "resolve": "^1.22.3", "sucrase": "^3.32.0" @@ -12596,8 +12596,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "license": "MIT", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", + "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -25441,7 +25442,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.11", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", + "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -27114,7 +27117,7 @@ "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.12", "postcss-value-parser": "^4.2.0", "prettier": "^2.8.8", "resolve": "^1.22.3", @@ -36091,7 +36094,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.11", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.12.tgz", + "integrity": "sha512-NdxGCAZdRrwVI1sy59+Wzrh+pMMHxapGnpfenDVlMEXoOcvt4pGE0JLK9YY2F5dLxcFYA/YbVQKhcGU+FtSYQg==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" diff --git a/package.json b/package.json index 476615caf..d74c2dcae 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "@swc/register": "^0.1.10", "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", - "cssnano": "^6.0.0", + "cssnano": "^6.0.1", "esbuild": "^0.17.18", "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", From ae5d746226f6096616de0cf320fae07347a9a460 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 23:41:53 +0000 Subject: [PATCH 19/85] Update sass to version 1.62.1 --- integrations/rollup-sass/package.json | 2 +- package-lock.json | 140 +++++++++++++++++--------- 2 files changed, 91 insertions(+), 51 deletions(-) diff --git a/integrations/rollup-sass/package.json b/integrations/rollup-sass/package.json index b1eaa6e94..38f86496a 100644 --- a/integrations/rollup-sass/package.json +++ b/integrations/rollup-sass/package.json @@ -20,6 +20,6 @@ "devDependencies": { "rollup": "^3.21.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "^1.62.1" } } diff --git a/package-lock.json b/package-lock.json index 5d978794c..fffad06d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,7 +51,7 @@ "@swc/register": "^0.1.10", "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", - "cssnano": "^6.0.0", + "cssnano": "^6.0.1", "esbuild": "^0.17.18", "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", @@ -104,7 +104,7 @@ "devDependencies": { "rollup": "^3.21.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "1.62.1" } }, "integrations/tailwindcss-cli": { @@ -6687,12 +6687,12 @@ } }, "node_modules/cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", + "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", "dev": true, "dependencies": { - "cssnano-preset-default": "^6.0.0", + "cssnano-preset-default": "^6.0.1", "lilconfig": "^2.1.0" }, "engines": { @@ -6707,14 +6707,14 @@ } }, "node_modules/cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", + "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", "dev": true, "dependencies": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", + "postcss-calc": "^9.0.0", "postcss-colormin": "^6.0.0", "postcss-convert-values": "^6.0.0", "postcss-discard-comments": "^6.0.0", @@ -6722,7 +6722,7 @@ "postcss-discard-empty": "^6.0.0", "postcss-discard-overridden": "^6.0.0", "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", + "postcss-merge-rules": "^6.0.1", "postcss-minify-font-values": "^6.0.0", "postcss-minify-gradients": "^6.0.0", "postcss-minify-params": "^6.0.0", @@ -6749,6 +6749,22 @@ "postcss": "^8.2.15" } }, + "node_modules/cssnano-preset-default/node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, "node_modules/cssnano-utils": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", @@ -12218,9 +12234,9 @@ } }, "node_modules/postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", + "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", "dev": true, "dependencies": { "browserslist": "^4.21.4", @@ -13973,9 +13989,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", - "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz", + "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -18920,7 +18936,7 @@ "requires": { "rollup": "^3.21.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "1.62.1" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -21205,24 +21221,24 @@ "version": "3.0.0" }, "cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", + "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", "dev": true, "requires": { - "cssnano-preset-default": "^6.0.0", + "cssnano-preset-default": "^6.0.1", "lilconfig": "^2.1.0" } }, "cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", + "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", "dev": true, "requires": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", + "postcss-calc": "^9.0.0", "postcss-colormin": "^6.0.0", "postcss-convert-values": "^6.0.0", "postcss-discard-comments": "^6.0.0", @@ -21230,7 +21246,7 @@ "postcss-discard-empty": "^6.0.0", "postcss-discard-overridden": "^6.0.0", "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", + "postcss-merge-rules": "^6.0.1", "postcss-minify-font-values": "^6.0.0", "postcss-minify-gradients": "^6.0.0", "postcss-minify-params": "^6.0.0", @@ -21249,6 +21265,18 @@ "postcss-reduce-transforms": "^6.0.0", "postcss-svgo": "^6.0.0", "postcss-unique-selectors": "^6.0.0" + }, + "dependencies": { + "postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + } + } } }, "cssnano-utils": { @@ -25211,9 +25239,9 @@ } }, "postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", + "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", "dev": true, "requires": { "browserslist": "^4.21.4", @@ -26388,9 +26416,9 @@ "dev": true }, "sass": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", - "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz", + "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -27093,7 +27121,7 @@ "browserslist": "^4.21.5", "chokidar": "^3.5.3", "concurrently": "^8.0.1", - "cssnano": "^6.0.0", + "cssnano": "^6.0.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "esbuild": "^0.17.18", @@ -29572,7 +29600,7 @@ "requires": { "rollup": "^3.21.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.0" + "sass": "1.62.1" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -31857,24 +31885,24 @@ "version": "3.0.0" }, "cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", + "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", "dev": true, "requires": { - "cssnano-preset-default": "^6.0.0", + "cssnano-preset-default": "^6.0.1", "lilconfig": "^2.1.0" } }, "cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", + "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", "dev": true, "requires": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", + "postcss-calc": "^9.0.0", "postcss-colormin": "^6.0.0", "postcss-convert-values": "^6.0.0", "postcss-discard-comments": "^6.0.0", @@ -31882,7 +31910,7 @@ "postcss-discard-empty": "^6.0.0", "postcss-discard-overridden": "^6.0.0", "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", + "postcss-merge-rules": "^6.0.1", "postcss-minify-font-values": "^6.0.0", "postcss-minify-gradients": "^6.0.0", "postcss-minify-params": "^6.0.0", @@ -31901,6 +31929,18 @@ "postcss-reduce-transforms": "^6.0.0", "postcss-svgo": "^6.0.0", "postcss-unique-selectors": "^6.0.0" + }, + "dependencies": { + "postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + } + } } }, "cssnano-utils": { @@ -35863,9 +35903,9 @@ } }, "postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", + "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", "dev": true, "requires": { "browserslist": "^4.21.4", @@ -37040,9 +37080,9 @@ "dev": true }, "sass": { - "version": "1.62.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.0.tgz", - "integrity": "sha512-Q4USplo4pLYgCi+XlipZCWUQz5pkg/ruSSgJ0WRDSb/+3z9tXUOkQ7QPYn4XrhZKYAK4HlpaQecRwKLJX6+DBg==", + "version": "1.62.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz", + "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", From 80415ece5e8ec8cb9871ae41f6e7415e4942be27 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 10 May 2023 19:44:03 +0200 Subject: [PATCH 20/85] Support `@import "tailwindcss"` using top-level `index.css` file (#11205) * make `@import "tailwindcss"` work out of the box * update changelog --- CHANGELOG.md | 1 + index.css | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 index.css diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a6d4ff90..f61138f1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) +- Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205)) ### Changed diff --git a/index.css b/index.css new file mode 100644 index 000000000..7f393742a --- /dev/null +++ b/index.css @@ -0,0 +1,5 @@ +@tailwind base; + +@tailwind components; + +@tailwind utilities; From dce8280d76a97f6ee35c282a7898b166f082ecd6 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Fri, 12 May 2023 10:13:29 -0400 Subject: [PATCH 21/85] [Oxide] Automatic content detection (#11173) * resolve all _existing_ content paths * pin `@napi-rs/cli` * WIP: Log all resolved content files/globs * only filter out raw changed content in non-auto mode * skip parseCandidateFiles cache in `auto` mode * improve algorithm of detecting content paths 1. Files in the root should be listed statically instead of using globs. 2. Files and folders in special known direct child folders should be listed statically instead of using globs (e.g.: `public`). This is because these special folders are often used to store generated AND source files at the same time. Using globs could trigger infinite loops because we are watching and acting upon dist files. 3. All file extensions found in the project, should be used in the globs in addition to a known set of extensions. 4. Direct folders seen from the root, can use the glob syntax `/src/**/*.{...known-extensions}` * inline wanted-extensions Not 100% convinced yet, but seems cleaner so far. * ensure writing an file also makes the parent folder(s) * add integration tests for the auto content feature * add pnpm and bun lock files * Revert "inline wanted-extensions" This reverts commit 879c1248524e84216125f4a24e0160b40736333a. * sort binary-extensions and add lockb * sort + add `lock` to ignored extensions * drop `yarn.lock`, because lock extensions are already covered * group template extensions This will make it a bit easier to organize in the future. * drop empty lines and commented lines from template-extensions * skip the config path when resolving template files The config file will automatically trigger a rebuild when this file is changed. However, this should not be part of the template files because that could cause additional css that's not being used. * make `auto content` the default in the oxide engine - In the oxide engine, the default `content: []` will be dropped from the default configuration (config.simple.js, config.full.js). - If you have `content: []` or `content: { files: [] }` then the auto content feature won't be active. However if those arrays are empty a warning will still be shown. Adding files/globs or dropping the `content` section completely will enable auto content. * only test the auto content integration test in the oxide engine * set `content.files` to `auto` instead of using `auto: boolean` This way we don't run into the issue where the `config.content.files` is set and the `config.content.auto` is set to true. * drop log * ensure we validate the config in the CLI * show experimental warning for automatic content detection * use cached version of the getCandidateFiles instead of bypassing it * use `is_empty()` shorthand Thanks, Clippy! * add test to ensure nested ignored folders are not scanned * add `tempfile` for tests * add auto content tests in Rust * refactor auto content detection This will also make sure that if we have (deeply) nested ignored folders, then we won't use deeply nested globs (**/*.{js,html}) for the parent(s) of the nested ignored folders but instead use a shallow glob for each directory (*/*.{js,html}). Then each sibling directory of the parent can use deeply nested globs again except for the direct parent. * use consistent comments * ensure ignored static listed files are not present * improve performance by ~30x On a big test project this goes from ~6s to ~200ms * improve performance by ~5x We started with a ~6s duration Then in the previous commit, we improved it by ~30x and it went down to ~200ms Now with this change, it takes about ~40ms. That's another ~5x improvement. Or in total a ~150x improvement. * ensure nested folders in `public/` are also explicitly listed * add shortcut for normalizing files This is only called once so won't do anything to the main performance of Tailwind CSS. But always nice to make small performance improvements! * run Rust tests in CI * fix lint warnings * update changelog * Update CHANGELOG.md --------- Co-authored-by: Robin Malfait --- .github/workflows/ci.yml | 10 +- CHANGELOG.md | 1 + integrations/io.js | 11 + .../fixtures/example-app/src/index.css | 3 + .../fixtures/example-app/src/index.html | 1 + .../tailwindcss-cli/tests/integration.test.js | 433 ++++++++++++++++++ oxide/Cargo.lock | 271 ++++++++++- oxide/crates/core/Cargo.toml | 3 + .../core/src/fixtures/binary-extensions.txt | 259 +++++++++++ .../core/src/fixtures/ignored-extensions.txt | 6 + .../core/src/fixtures/ignored-files.txt | 3 + .../core/src/fixtures/template-extensions.txt | 57 +++ oxide/crates/core/src/lib.rs | 281 +++++++++++- oxide/crates/core/src/parser.rs | 4 +- oxide/crates/core/tests/auto_content.rs | 248 ++++++++++ oxide/crates/node/package.json | 2 +- oxide/crates/node/src/lib.rs | 11 + package-lock.json | 6 +- src/cli/build/plugin.js | 9 +- src/cli/init/index.js | 5 + src/lib/content.js | 35 +- src/oxide/cli/build/plugin.ts | 9 +- src/oxide/cli/init/index.ts | 5 + src/util/getAllConfigs.js | 9 +- src/util/normalizeConfig.js | 68 ++- src/util/validateConfig.js | 9 +- tests/normalize-config.test.js | 4 +- tests/warnings.test.js | 6 +- 28 files changed, 1715 insertions(+), 54 deletions(-) create mode 100644 integrations/tailwindcss-cli/fixtures/example-app/src/index.css create mode 100644 integrations/tailwindcss-cli/fixtures/example-app/src/index.html create mode 100644 oxide/crates/core/src/fixtures/binary-extensions.txt create mode 100644 oxide/crates/core/src/fixtures/ignored-extensions.txt create mode 100644 oxide/crates/core/src/fixtures/ignored-files.txt create mode 100644 oxide/crates/core/src/fixtures/template-extensions.txt create mode 100644 oxide/crates/core/tests/auto_content.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3e2433d3b..b7e4a4674 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -65,11 +65,19 @@ jobs: - name: Build Tailwind CSS run: npx turbo run build --filter=// - - name: Test + - name: Test (Node.js) run: | npx turbo run test --filter=// || \ npx turbo run test --filter=// || \ npx turbo run test --filter=// || exit 1 + - name: Test (Rust) + run: | + cd ./oxide + cargo test || \ + cargo test || \ + cargo test || exit 1 + cd - + - name: Lint run: npx turbo run style --filter=// diff --git a/CHANGELOG.md b/CHANGELOG.md index f61138f1b..f7aa8bc7c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) - Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205)) +- [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173)) ### Changed diff --git a/integrations/io.js b/integrations/io.js index c555ac8ba..d30570d3a 100644 --- a/integrations/io.js +++ b/integrations/io.js @@ -122,6 +122,17 @@ module.exports = function ({ }, async writeInputFile(file, contents) { let filePath = path.resolve(absoluteInputFolder, file) + + // Ensure the parent folder of the file exists + if ( + !(await fs + .stat(filePath) + .then(() => true) + .catch(() => false)) + ) { + await fs.mkdir(path.dirname(filePath), { recursive: true }) + } + if (!fileCache[filePath]) { try { fileCache[filePath] = await fs.readFile(filePath, 'utf8') diff --git a/integrations/tailwindcss-cli/fixtures/example-app/src/index.css b/integrations/tailwindcss-cli/fixtures/example-app/src/index.css new file mode 100644 index 000000000..b5c61c956 --- /dev/null +++ b/integrations/tailwindcss-cli/fixtures/example-app/src/index.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/integrations/tailwindcss-cli/fixtures/example-app/src/index.html b/integrations/tailwindcss-cli/fixtures/example-app/src/index.html new file mode 100644 index 000000000..b956240c2 --- /dev/null +++ b/integrations/tailwindcss-cli/fixtures/example-app/src/index.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/integrations/tailwindcss-cli/tests/integration.test.js b/integrations/tailwindcss-cli/tests/integration.test.js index 75c9779af..de806dd27 100644 --- a/integrations/tailwindcss-cli/tests/integration.test.js +++ b/integrations/tailwindcss-cli/tests/integration.test.js @@ -1,4 +1,5 @@ let fs = require('fs') +let path = require('path') let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') let { env } = require('../../../lib/lib/sharedState') @@ -1000,4 +1001,436 @@ describe('watcher', () => { return runningProcess.stop() }) + + if (env.ENGINE === 'oxide') { + describe('auto content', () => { + let { readOutputFile, writeInputFile } = require('../../io')({ + output: 'fixtures/example-app/dist', + input: 'fixtures/example-app/src', + }) + let options = { + cwd: path.resolve(__dirname, '..', 'fixtures', 'example-app'), + } + + it('should detect classes in existing files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + + await writeInputFile('index.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + return runningProcess.stop() + }) + + it('should detect changes in existing files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + // Make a change + + await writeInputFile('index.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should detect changes in new files in existing folders with a known extension', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + // Make a change to a new file in an existing folder with a known extension. + + await writeInputFile('other.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan ignored files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('../.gitignore', 'generated-folder/') + await writeInputFile('../generated-folder/bad.html', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for known binary files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('example-1.png', html`
`) + await writeInputFile('example-2.mp4', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for explicitly ignored extensions (such as css/scss/less/...)', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('example.css', html`
`) + await writeInputFile('example.less', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for explicitly ignored files (such as package-lock.json)', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('package-lock.json', html`
`) + await writeInputFile('yarn.lock', html`
`) + await writeInputFile('pnpm-lock.yaml', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not include the tailwind.config.js file as a template file', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + // Example class that should not be included: flex italic + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .flex { + display: flex; + } + ` + ) + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should optimize the globs and ensure that nested ignored folders are not scanned', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('../.gitignore', 'node_modules') + await writeInputFile('../node_modules/a.html', html`
`) + await writeInputFile('index.html', html`
`) + await writeInputFile('nested/index.html', html`
`) + await writeInputFile( + 'nested/node_modules/index.html', + html`
` + ) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + // Root node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .text-red-100 { + color: #fee2e2; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .text-red-200 { + color: #fecaca; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .text-red-300 { + color: #fca5a5; + } + ` + ) + + // Nested node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .text-red-400 { + color: #f87171; + } + ` + ) + + return runningProcess.stop() + }) + }) + } }) diff --git a/oxide/Cargo.lock b/oxide/Cargo.lock index 5b959d726..948b8b4cc 100644 --- a/oxide/Cargo.lock +++ b/oxide/Cargo.lock @@ -17,7 +17,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -48,9 +48,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.0.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fca0852af221f458706eb0725c03e4ed6c46af9ac98e6a689d5e634215d594dd" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" dependencies = [ "memchr", "once_cell", @@ -76,6 +76,12 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -280,6 +286,36 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + [[package]] name = "fnv" version = "1.0.7" @@ -297,12 +333,12 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a1e17342619edbc21a964c2afbeb6c820c6a2560032872f397bb97ea127bd0a" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ "aho-corasick", - "bstr 0.2.17", + "bstr 1.4.0", "fnv", "log", "regex", @@ -341,12 +377,17 @@ dependencies = [ ] [[package]] -name = "ignore" -version = "0.4.18" +name = "hermit-abi" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" dependencies = [ - "crossbeam-utils", "globset", "lazy_static", "log", @@ -358,6 +399,26 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -396,9 +457,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.137" +version = "0.2.142" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" [[package]] name = "libloading" @@ -410,6 +471,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "linux-raw-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" + [[package]] name = "log" version = "0.4.17" @@ -523,7 +590,7 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", ] @@ -650,6 +717,15 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.7.0" @@ -676,6 +752,20 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + [[package]] name = "ryu" version = "1.0.11" @@ -786,15 +876,18 @@ version = "0.1.0" name = "tailwindcss-core" version = "0.1.0" dependencies = [ - "bstr 1.0.1", + "bstr 1.4.0", "criterion", "crossbeam", "fxhash", "globwalk", + "ignore", "log", "rayon", + "tempfile", "tracing", "tracing-subscriber", + "walkdir", ] [[package]] @@ -806,6 +899,19 @@ dependencies = [ "tailwindcss-core", ] +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.45.0", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -937,12 +1043,11 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] @@ -1040,3 +1145,135 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/oxide/crates/core/Cargo.toml b/oxide/crates/core/Cargo.toml index ae895f34a..0db8eb2b2 100644 --- a/oxide/crates/core/Cargo.toml +++ b/oxide/crates/core/Cargo.toml @@ -12,9 +12,12 @@ fxhash = "0.2.1" crossbeam = "0.8.2" tracing = { version = "0.1.37", features = [] } tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } +walkdir = "2.3.3" +ignore = "0.4.20" [dev-dependencies] criterion = { version = "0.3", features = ['html_reports'] } +tempfile = "3.5.0" [[bench]] name = "parse_candidates" diff --git a/oxide/crates/core/src/fixtures/binary-extensions.txt b/oxide/crates/core/src/fixtures/binary-extensions.txt new file mode 100644 index 000000000..b7cee312c --- /dev/null +++ b/oxide/crates/core/src/fixtures/binary-extensions.txt @@ -0,0 +1,259 @@ +3dm +3ds +3g2 +3gp +7z +DS_Store +a +aac +adp +ai +aif +aiff +alz +ape +apk +appimage +ar +arj +asf +au +avi +bak +baml +bh +bin +bk +bmp +btif +bz2 +bzip2 +cab +caf +cgm +class +cmx +cpio +cr2 +cur +dat +dcm +deb +dex +djvu +dll +dmg +dng +doc +docm +docx +dot +dotm +dra +dsk +dts +dtshd +dvb +dwg +dxf +ecelp4800 +ecelp7470 +ecelp9600 +egg +eol +eot +epub +exe +f4v +fbs +fh +fla +flac +flatpak +fli +flv +fpx +fst +fvt +g3 +gh +gif +graffle +gz +gzip +h261 +h263 +h264 +icns +ico +ief +img +ipa +iso +jar +jpeg +jpg +jpgv +jpm +jxr +key +ktx +lha +lib +lockb +lvp +lz +lzh +lzma +lzo +m3u +m4a +m4v +mar +mdi +mht +mid +midi +mj2 +mka +mkv +mmr +mng +mobi +mov +movie +mp3 +mp4 +mp4a +mpeg +mpg +mpga +mxu +nef +npx +numbers +nupkg +o +odp +ods +odt +oga +ogg +ogv +otf +ott +pages +pbm +pcx +pdb +pdf +pea +pgm +pic +png +pnm +pot +potm +potx +ppa +ppam +ppm +pps +ppsm +ppsx +ppt +pptm +pptx +psd +pya +pyc +pyo +pyv +qt +rar +ras +raw +resources +rgb +rip +rlc +rmf +rmvb +rpm +rtf +rz +s3m +s7z +scpt +sgi +shar +sil +sketch +slk +smv +snap +snk +so +stl +sub +suo +swf +tar +tbz +tbz2 +tga +tgz +thmx +tif +tiff +tlz +ttc +ttf +txz +udf +uvh +uvi +uvm +uvp +uvs +uvu +viv +vob +war +wav +wax +wbmp +wdp +weba +webm +webp +whl +wim +wm +wma +wmv +wmx +woff +woff2 +wrm +wvx +xbm +xif +xla +xlam +xls +xlsb +xlsm +xlsx +xlt +xltm +xltx +xm +xmind +xpi +xpm +xwd +xz +z +zip +zipx diff --git a/oxide/crates/core/src/fixtures/ignored-extensions.txt b/oxide/crates/core/src/fixtures/ignored-extensions.txt new file mode 100644 index 000000000..f147c24fe --- /dev/null +++ b/oxide/crates/core/src/fixtures/ignored-extensions.txt @@ -0,0 +1,6 @@ +css +less +lock +sass +scss +styl diff --git a/oxide/crates/core/src/fixtures/ignored-files.txt b/oxide/crates/core/src/fixtures/ignored-files.txt new file mode 100644 index 000000000..45d4ced87 --- /dev/null +++ b/oxide/crates/core/src/fixtures/ignored-files.txt @@ -0,0 +1,3 @@ +package-lock.json +pnpm-lock.yaml +bun.lockb diff --git a/oxide/crates/core/src/fixtures/template-extensions.txt b/oxide/crates/core/src/fixtures/template-extensions.txt new file mode 100644 index 000000000..c059eff3a --- /dev/null +++ b/oxide/crates/core/src/fixtures/template-extensions.txt @@ -0,0 +1,57 @@ +# HTML +html +pug + +# JS +astro +cjs +cts +jade +js +jsx +mjs +mts +svelte +ts +tsx +vue + +# Markdown +md +mdx + +# ASP +aspx +razor + +# Handlebars +handlebars +hbs +mustache + +# PHP +php +twig + +# Ruby +erb +haml +liquid +rb +rhtml +slim + +# Elixir / Phoenix +eex +heex + +# Nunjucks +njk +nunjucks + +# Python +py +tpl + +# Rust +rs diff --git a/oxide/crates/core/src/lib.rs b/oxide/crates/core/src/lib.rs index 9dd88437d..6601267fd 100644 --- a/oxide/crates/core/src/lib.rs +++ b/oxide/crates/core/src/lib.rs @@ -1,8 +1,12 @@ use crate::parser::Extractor; use fxhash::FxHashSet; +use ignore::WalkBuilder; use rayon::prelude::*; +use std::cmp::Ordering; +use std::path::Path; use std::path::PathBuf; use tracing::event; +use walkdir::WalkDir; pub mod candidate; pub mod glob; @@ -30,6 +34,275 @@ pub struct ChangedContent { pub extension: String, } +#[derive(Debug, Clone)] +pub struct ContentPathInfo { + pub base: String, +} + +pub fn resolve_content_paths(args: ContentPathInfo) -> Vec { + let root = Path::new(&args.base); + + let allowed_paths = FxHashSet::from_iter( + WalkBuilder::new(&root) + .hidden(false) + .filter_entry(|entry| match entry.file_type() { + Some(file_type) if file_type.is_dir() => entry + .file_name() + .to_str() + .map(|s| s != ".git") + .unwrap_or(false), + _ => true, + }) + .build() + .filter_map(Result::ok) + .map(|x| x.into_path()), + ); + + // A list of directory names where we can't use globs, but we should track each file + // individually instead. This is because these directories are often used for both source and + // destination files. + let mut forced_static_directories = vec![root.join("public")]; + + // A list of known extensions + a list of extensions we found in the project. + let mut found_extensions = FxHashSet::from_iter( + include_str!("fixtures/template-extensions.txt") + .trim() + .lines() + .filter(|x| !x.starts_with('#')) // Drop commented lines + .filter(|x| !x.is_empty()) // Drop empty lines + .map(|x| x.to_string()), + ); + + // A list of static files that we should track directly. + let mut static_files = vec![]; + + // All root directories. + let mut root_directories = FxHashSet::from_iter(vec![root.to_path_buf()]); + + // All directories where we can safely use deeply nested globs to watch all files. + // In other comments we refer to these as "deep glob directories" or similar. + // + // E.g.: ./src/**/*.{html,js} + let mut deep_globable_directories: FxHashSet = FxHashSet::default(); + + // All directories where we can only use shallow globs to watch all direct files but not + // folders. + // In other comments we refer to these as "shallow glob directories" or similar. + // + // E.g.: ./src/*/*.{html,js} + let mut shallow_globable_directories: FxHashSet = FxHashSet::default(); + + // Collect all valid paths from the root. This will already filter out ignored files, unknown + // extensions and binary files. + let mut it = WalkDir::new(&root) + // Sorting to make sure that we always see the directories before the files. Also sorting + // alphabetically by default. + .sort_by( + |a, z| match (a.file_type().is_dir(), z.file_type().is_dir()) { + (true, false) => Ordering::Less, + (false, true) => Ordering::Greater, + _ => a.file_name().cmp(z.file_name()), + }, + ) + .into_iter(); + + loop { + // We are only interested in valid entries + let entry = match it.next() { + Some(Ok(entry)) => entry, + _ => break, + }; + + // Ignore known directories that we don't want to traverse into. + if entry.file_type().is_dir() && entry.file_name() == ".git" { + it.skip_current_dir(); + continue; + } + + if entry.file_type().is_dir() { + // If we are in a directory where we know that we can't use any globs, then we have to + // track each file individually. + if forced_static_directories.contains(&entry.path().to_path_buf()) { + forced_static_directories.push(entry.path().to_path_buf()); + root_directories.insert(entry.path().to_path_buf()); + continue; + } + + // If we are in a directory where the parent is a forced static directory, then this + // will become a forced static directory as well. + if forced_static_directories.contains(&entry.path().parent().unwrap().to_path_buf()) { + forced_static_directories.push(entry.path().to_path_buf()); + root_directories.insert(entry.path().to_path_buf()); + continue; + } + + // If we are in a directory, and the directory is git ignored, then we don't have to + // descent into the directory. However, we have to make sure that we mark the _parent_ + // directory as a shallow glob directory because using deep globs from any of the + // parent directories will include this ignored directory which should not be the case. + // + // Another important part is that if one of the ignored directories is a deep glob + // directory, then all of its parents (until the root) should be marked as shallow glob + // directories as well. + if !allowed_paths.contains(&entry.path().to_path_buf()) { + let mut parent = entry.path().parent(); + while let Some(parent_path) = parent { + // If the parent is already marked as a valid deep glob directory, then we have + // to mark it as a shallow glob directory instead, because we won't be able to + // use deep globs for this directory anymore. + if deep_globable_directories.contains(parent_path) { + deep_globable_directories.remove(parent_path); + shallow_globable_directories.insert(parent_path.to_path_buf()); + } + + // If we reached the root, then we can stop. + if parent_path == root { + break; + } + + // Mark the parent directory as a shallow glob directory and continue with its + // parent. + shallow_globable_directories.insert(parent_path.to_path_buf()); + parent = parent_path.parent(); + } + + it.skip_current_dir(); + continue; + } + // If we are in a directory that is not git ignored, then we can mark this directory as + // a valid deep glob directory. This is only necessary if any of its parents aren't + // marked as deep glob directories already. + else { + let mut found_deep_glob_parent = false; + let mut parent = entry.path().parent(); + while let Some(parent_path) = parent { + // If we reached the root, then we can stop. + if parent_path == root { + break; + } + + // If the parent is already marked as a deep glob directory, then we can stop + // because this glob will match the current directory already. + if deep_globable_directories.contains(parent_path) { + found_deep_glob_parent = true; + break; + } + + parent = parent_path.parent(); + } + + // If we didn't find a deep glob directory parent, then we can mark this directory + // as a deep glob directory (unless it is the root). + if !found_deep_glob_parent && entry.path() != root { + deep_globable_directories.insert(entry.path().to_path_buf()); + } + } + } + + // Handle allowed content paths + if is_allowed_content_path(entry.path()) + && allowed_paths.contains(&entry.path().to_path_buf()) + { + let path = entry.path(); + + // Collect the extension for future use when building globs. + if let Some(extension) = path.extension().and_then(|x| x.to_str()) { + found_extensions.insert(extension.to_string()); + } + + // If the current path is a file inside any of the root directories, then we have to + // track it directly as a static file. + if let Some(parent_path) = path.parent() { + if root_directories.contains(parent_path) { + static_files.push(format!("{}", path.display())); + } + } + } + } + + // Build the globs for all globable directories. + let shallow_globs = shallow_globable_directories + .iter() + .map(|path| format!("{}", path.display())); + let deep_globs = deep_globable_directories + .iter() + .map(|path| format!("{}/**", path.display())); + let globs = shallow_globs + .chain(deep_globs) + .flat_map(|path| match found_extensions.len() { + 0 => None, // This should never happen + 1 => Some(format!( + "{}/*.{}", + path, + found_extensions.iter().next().unwrap() + )), + _ => Some(format!( + "{}/*.{{{}}}", + path, + found_extensions + .iter() + .map(|x| x.to_string()) + .collect::>() + .join(","), + )), + }) + .collect::>(); + + static_files.extend(globs); + static_files +} + +pub fn is_git_ignored_content_path(base: &Path, path: &Path) -> bool { + !WalkBuilder::new(base) + .hidden(false) + .filter_entry(|entry| match entry.file_type() { + Some(file_type) if file_type.is_dir() => entry + .file_name() + .to_str() + .map(|s| s != ".git") + .unwrap_or(false), + _ => true, + }) + .build() + .filter_map(Result::ok) + .any(|e| e.path() == path) +} + +pub fn is_allowed_content_path(path: &Path) -> bool { + let binary_extensions = include_str!("fixtures/binary-extensions.txt") + .trim() + .lines() + .collect::>(); + let ignored_extensions = include_str!("fixtures/ignored-extensions.txt") + .trim() + .lines() + .collect::>(); + let ignored_files = include_str!("fixtures/ignored-files.txt") + .trim() + .lines() + .collect::>(); + + let path = PathBuf::from(path); + + // Skip known ignored files + if path + .file_name() + .unwrap() + .to_str() + .map(|s| ignored_files.contains(&s)) + .unwrap_or(false) + { + return false; + } + + // Skip known ignored extensions + return path + .extension() + .map(|s| s.to_str().unwrap_or_default()) + .map(|ext| !ignored_extensions.contains(&ext) && !binary_extensions.contains(&ext)) + .unwrap_or(false); +} + #[derive(Debug)] pub enum IO { Sequential = 0b0001, @@ -89,7 +362,13 @@ fn read_all_files(changed_content: Vec) -> Vec> { changed_content .into_par_iter() .map(|c| match (c.file, c.content) { - (Some(file), None) => std::fs::read(file).unwrap(), + (Some(file), None) => match std::fs::read(file) { + Ok(content) => content, + Err(e) => { + event!(tracing::Level::ERROR, "Failed to read file: {:?}", e); + Default::default() + } + }, (None, Some(content)) => content.into_bytes(), _ => Default::default(), }) diff --git a/oxide/crates/core/src/parser.rs b/oxide/crates/core/src/parser.rs index 16831afff..372758e8e 100644 --- a/oxide/crates/core/src/parser.rs +++ b/oxide/crates/core/src/parser.rs @@ -352,7 +352,7 @@ impl<'a> Extractor<'a> { self.in_candidate && !self.in_arbitrary && (0..=127).contains(&c) - && (self.idx_start == 0 || self.input[(self.idx_start - 1)] <= 127) + && (self.idx_start == 0 || self.input[self.idx_start - 1] <= 127) } #[inline(always)] @@ -470,7 +470,7 @@ impl<'a> Iterator for Extractor<'a> { mod test { use super::*; - fn please_trace() { + fn _please_trace() { tracing_subscriber::fmt() .with_max_level(tracing::Level::TRACE) .with_span_events(tracing_subscriber::fmt::format::FmtSpan::ACTIVE) diff --git a/oxide/crates/core/tests/auto_content.rs b/oxide/crates/core/tests/auto_content.rs new file mode 100644 index 000000000..f7a185f6c --- /dev/null +++ b/oxide/crates/core/tests/auto_content.rs @@ -0,0 +1,248 @@ +#[cfg(test)] +mod auto_content { + use std::fs; + use std::process::Command; + + use tailwindcss_core::*; + use tempfile::tempdir; + + fn test(paths_with_content: &[(&str, Option<&str>)]) -> Vec { + // Create a temporary working directory + let dir = tempdir().unwrap().into_path(); + + // Initialize this directory as a git repository + let _ = Command::new("git").arg("init").current_dir(&dir).output(); + + // Create the necessary files + for (path, contents) in paths_with_content { + let path = dir.join(path); + let parent = path.parent().unwrap(); + if !parent.exists() { + fs::create_dir_all(parent).unwrap(); + } + + match contents { + Some(contents) => fs::write(path, contents).unwrap(), + None => fs::write(path, "").unwrap(), + } + } + + let base = format!("{}", dir.display()); + + // Resolve all content paths for the (temporary) current working directory + let mut paths: Vec<_> = resolve_content_paths(ContentPathInfo { base: base.clone() }) + .into_iter() + .map(|x| x.replace(&format!("{}/", &base), "")) + .collect(); + + // Sort the output for easier comparison (depending on internal datastructure the order + // _could_ be random) + paths.sort(); + + paths + } + + #[test] + fn it_should_work_with_a_set_of_root_files() { + let globs = test(&[ + ("index.html", None), + ("a.html", None), + ("b.html", None), + ("c.html", None), + ]); + assert_eq!(globs, vec!["a.html", "b.html", "c.html", "index.html"]); + } + + #[test] + fn it_should_work_with_a_set_of_root_files_and_ignore_ignored_files() { + let globs = test(&[ + (".gitignore", Some("b.html")), + ("index.html", None), + ("a.html", None), + ("b.html", None), + ("c.html", None), + ]); + assert_eq!(globs, vec!["a.html", "c.html", "index.html"]); + } + + #[test] + fn it_should_list_all_files_in_the_public_folder_explicitly() { + let globs = test(&[ + ("index.html", None), + ("public/a.html", None), + ("public/b.html", None), + ("public/c.html", None), + ]); + assert_eq!( + globs, + vec![ + "index.html", + "public/a.html", + "public/b.html", + "public/c.html", + ] + ); + } + + #[test] + fn it_should_list_nested_folders_explicitly_in_the_public_folder() { + let globs = test(&[ + ("index.html", None), + ("public/a.html", None), + ("public/b.html", None), + ("public/c.html", None), + ("public/nested/a.html", None), + ("public/nested/b.html", None), + ("public/nested/c.html", None), + ("public/nested/again/a.html", None), + ("public/very/deeply/nested/a.html", None), + ]); + assert_eq!( + globs, + vec![ + "index.html", + "public/a.html", + "public/b.html", + "public/c.html", + "public/nested/a.html", + "public/nested/again/a.html", + "public/nested/b.html", + "public/nested/c.html", + "public/very/deeply/nested/a.html", + ] + ); + } + + #[test] + fn it_should_list_all_files_in_the_public_folder_explicitly_except_ignored_files() { + let globs = test(&[ + (".gitignore", Some("public/b.html\na.html")), + ("index.html", None), + ("public/a.html", None), + ("public/b.html", None), + ("public/c.html", None), + ]); + assert_eq!(globs, vec!["index.html", "public/c.html",]); + } + + #[test] + fn it_should_use_a_glob_for_top_level_folders() { + let globs = test(&[ + ("index.html", None), + ("src/a.html", None), + ("src/b.html", None), + ("src/c.html", None), + ]); + assert_eq!(globs, vec!["index.html", "src/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}"]); + } + + #[test] + fn it_should_ignore_binary_files() { + let globs = test(&[ + ("index.html", None), + ("a.mp4", None), + ("b.png", None), + ("c.lock", None), + ]); + assert_eq!(globs, vec!["index.html"]); + } + + #[test] + fn it_should_ignore_known_extensions() { + let globs = test(&[ + ("index.html", None), + ("a.css", None), + ("b.sass", None), + ("c.less", None), + ]); + assert_eq!(globs, vec!["index.html"]); + } + + #[test] + fn it_should_ignore_known_files() { + let globs = test(&[ + ("index.html", None), + ("package-lock.json", None), + ("yarn.lock", None), + ]); + assert_eq!(globs, vec!["index.html"]); + } + + #[test] + fn it_should_ignore_and_expand_nested_ignored_folders() { + let globs = test(&[ + // Explicitly listed root files + ("foo.html", None), + ("bar.html", None), + ("baz.html", None), + // Nested folder A, using glob + ("nested-a/foo.html", None), + ("nested-a/bar.html", None), + ("nested-a/baz.html", None), + // Nested folder B, with deeply nested files, using glob + ("nested-b/deeply-nested/foo.html", None), + ("nested-b/deeply-nested/bar.html", None), + ("nested-b/deeply-nested/baz.html", None), + // Nested folder C, with ignored sub-folder + ("nested-c/foo.html", None), + ("nested-c/bar.html", None), + ("nested-c/baz.html", None), + // Ignored folder + ("nested-c/.gitignore", Some("ignored-folder/")), + ("nested-c/ignored-folder/foo.html", None), + ("nested-c/ignored-folder/bar.html", None), + ("nested-c/ignored-folder/baz.html", None), + // Deeply nested, without issues + ("nested-c/sibling-folder/foo.html", None), + ("nested-c/sibling-folder/bar.html", None), + ("nested-c/sibling-folder/baz.html", None), + // Nested folder D, with deeply nested ignored folder + ("nested-d/foo.html", None), + ("nested-d/bar.html", None), + ("nested-d/baz.html", None), + ("nested-d/.gitignore", Some("deep/")), + ("nested-d/very/deeply/nested/deep/foo.html", None), + ("nested-d/very/deeply/nested/deep/bar.html", None), + ("nested-d/very/deeply/nested/deep/baz.html", None), + ("nested-d/very/deeply/nested/foo.html", None), + ("nested-d/very/deeply/nested/bar.html", None), + ("nested-d/very/deeply/nested/baz.html", None), + ("nested-d/very/deeply/nested/directory/foo.html", None), + ("nested-d/very/deeply/nested/directory/bar.html", None), + ("nested-d/very/deeply/nested/directory/baz.html", None), + ("nested-d/very/deeply/nested/directory/again/foo.html", None), + ]); + + assert_eq!( + globs, + vec![ + // Listed explicitly because they are in the root + "bar.html", + "baz.html", + "foo.html", + + // Listed using a deep glob, because nothing inside is ignored + "nested-a/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // Listed using a deep glob, because nothing inside is ignored (but contains deeply + // nested folders) + "nested-b/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // Listed using a shallow glob, because `nested-c` contains ignored folders, deeply + // nested globs can't be used anymore + "nested-c/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // Deeply nested folder can use a deep glob again + "nested-c/sibling-folder/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + + // The deeply nested folder can use a deep glob, however all of its parents can + // only contain a shallow glob because of the ignored folder + "nested-d/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/deeply/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/deeply/nested/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + "nested-d/very/deeply/nested/directory/**/*.{py,tpl,js,vue,php,mjs,cts,jsx,tsx,rhtml,slim,handlebars,twig,rs,njk,svelte,liquid,pug,md,ts,heex,mts,astro,nunjucks,rb,eex,haml,cjs,html,hbs,jade,aspx,razor,erb,mustache,mdx}", + ] + ); + } +} diff --git a/oxide/crates/node/package.json b/oxide/crates/node/package.json index f9841b69f..80ddc6fcf 100644 --- a/oxide/crates/node/package.json +++ b/oxide/crates/node/package.json @@ -19,7 +19,7 @@ }, "license": "MIT", "devDependencies": { - "@napi-rs/cli": "^2.15.2" + "@napi-rs/cli": "2.15.2" }, "engines": { "node": ">= 10" diff --git a/oxide/crates/node/src/lib.rs b/oxide/crates/node/src/lib.rs index f8b927db5..82bf28b0a 100644 --- a/oxide/crates/node/src/lib.rs +++ b/oxide/crates/node/src/lib.rs @@ -29,6 +29,17 @@ pub fn parse_candidate_strings_from_files(changed_content: Vec) ) } +#[derive(Debug, Clone)] +#[napi(object)] +pub struct ContentPathInfo { + pub base: String, +} + +#[napi] +pub fn resolve_content_paths(args: ContentPathInfo) -> Vec { + tailwindcss_core::resolve_content_paths(tailwindcss_core::ContentPathInfo { base: args.base }) +} + #[derive(Debug)] #[napi] pub enum IO { diff --git a/package-lock.json b/package-lock.json index fffad06d0..af4967b34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16472,7 +16472,7 @@ "version": "0.0.0", "license": "MIT", "devDependencies": { - "@napi-rs/cli": "^2.15.2" + "@napi-rs/cli": "2.15.2" }, "engines": { "node": ">= 10" @@ -19253,7 +19253,7 @@ "@tailwindcss/oxide": { "version": "file:oxide/crates/node", "requires": { - "@napi-rs/cli": "^2.15.2", + "@napi-rs/cli": "2.15.2", "@tailwindcss/oxide-darwin-arm64": "0.0.0", "@tailwindcss/oxide-darwin-x64": "0.0.0", "@tailwindcss/oxide-freebsd-x64": "0.0.0", @@ -29917,7 +29917,7 @@ "@tailwindcss/oxide": { "version": "file:oxide/crates/node", "requires": { - "@napi-rs/cli": "^2.15.2", + "@napi-rs/cli": "2.15.2", "@tailwindcss/oxide-darwin-arm64": "0.0.0", "@tailwindcss/oxide-darwin-x64": "0.0.0", "@tailwindcss/oxide-freebsd-x64": "0.0.0", diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index 9f3f6f52f..a5045593d 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -19,6 +19,7 @@ import { findAtConfigPath } from '../../lib/findAtConfigPath.js' import log from '../../util/log' import { loadConfig } from '../../lib/load-config' import getModuleDependencies from '../../lib/getModuleDependencies' +import { validateConfig } from '../../util/validateConfig' /** * @@ -161,7 +162,13 @@ let state = { } // @ts-ignore - this.configBag.config = resolveConfig(this.configBag.config, { content: { files: [] } }) + if (__OXIDE__) { + this.configBag.config = validateConfig(resolveConfig(this.configBag.config)) + } else { + this.configBag.config = validateConfig( + resolveConfig(this.configBag.config, { content: { files: [] } }) + ) + } // Override content files if `--content` has been passed explicitly if (content?.length > 0) { diff --git a/src/cli/init/index.js b/src/cli/init/index.js index 6bd7e41e2..ac118549a 100644 --- a/src/cli/init/index.js +++ b/src/cli/init/index.js @@ -38,6 +38,11 @@ export function init(args) { 'utf8' ) + // Drop `content` in the oxide engine to promote auto content + if (__OXIDE__) { + stubContentsFile = stubContentsFile.replace(/\s*content: \[\],\n/, '') + } + // Change colors import stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors') diff --git a/src/lib/content.js b/src/lib/content.js index e814efe4d..7b58e9d67 100644 --- a/src/lib/content.js +++ b/src/lib/content.js @@ -11,6 +11,28 @@ import { env } from './sharedState' /** @typedef {import('../../types/config.js').RawFile} RawFile */ /** @typedef {import('../../types/config.js').FilePath} FilePath */ +/* + * @param {import('tailwindcss').Config} tailwindConfig + * @param {{skip:string[]}} options + * @returns {ContentPath[]} + */ +function resolveContentFiles(tailwindConfig, { skip = [] } = {}) { + if (tailwindConfig.content.files === 'auto' && __OXIDE__) { + env.DEBUG && console.time('Calculating resolve content paths') + tailwindConfig.content.files = require('@tailwindcss/oxide').resolveContentPaths({ + base: process.cwd(), + }) + if (skip.length > 0) { + tailwindConfig.content.files = tailwindConfig.content.files.filter( + (filePath) => !skip.includes(filePath) + ) + } + env.DEBUG && console.timeEnd('Calculating resolve content paths') + } + + return tailwindConfig.content.files +} + /** * @typedef {object} ContentPath * @property {string} original @@ -32,7 +54,9 @@ import { env } from './sharedState' * @returns {ContentPath[]} */ export function parseCandidateFiles(context, tailwindConfig) { - let files = tailwindConfig.content.files + let files = resolveContentFiles(tailwindConfig, { + skip: [context.userConfigPath], + }) // Normalize the file globs files = files.filter((filePath) => typeof filePath === 'string') @@ -167,9 +191,12 @@ function resolvePathSymlinks(contentPath) { * @returns {[{ content: string, extension: string }[], Map]} */ export function resolvedChangedContent(context, candidateFiles, fileModifiedMap) { - let changedContent = context.tailwindConfig.content.files - .filter((item) => typeof item.raw === 'string') - .map(({ raw, extension = 'html' }) => ({ content: raw, extension })) + let changedContent = + context.tailwindConfig.content.files === 'auto' && __OXIDE__ + ? [] + : context.tailwindConfig.content.files + .filter((item) => typeof item.raw === 'string') + .map(({ raw, extension = 'html' }) => ({ content: raw, extension })) let [changedFiles, mTimesToCommit] = resolveChangedFiles(candidateFiles, fileModifiedMap) diff --git a/src/oxide/cli/build/plugin.ts b/src/oxide/cli/build/plugin.ts index 4141ec439..aa9bb5b99 100644 --- a/src/oxide/cli/build/plugin.ts +++ b/src/oxide/cli/build/plugin.ts @@ -18,6 +18,7 @@ import log from '../../../util/log' import { loadConfig } from '../../../lib/load-config' import getModuleDependencies from '../../../lib/getModuleDependencies' import type { Config } from '../../../../types' +import { validateConfig } from '../../../util/validateConfig' /** * @@ -160,7 +161,13 @@ let state = { } // @ts-ignore - this.configBag.config = resolveConfig(this.configBag.config, { content: { files: [] } }) + if (__OXIDE__) { + this.configBag.config = validateConfig(resolveConfig(this.configBag.config)) + } else { + this.configBag.config = validateConfig( + resolveConfig(this.configBag.config, { content: { files: [] } }) + ) + } // Override content files if `--content` has been passed explicitly if (content?.length > 0) { diff --git a/src/oxide/cli/init/index.ts b/src/oxide/cli/init/index.ts index abc93cdc1..b05138349 100644 --- a/src/oxide/cli/init/index.ts +++ b/src/oxide/cli/init/index.ts @@ -36,6 +36,11 @@ export function init(args) { 'utf8' ) + // Drop `content` in the oxide engine to promote auto content + if (__OXIDE__) { + stubContentsFile = stubContentsFile.replace(/\s*content: \[\],\n/, '') + } + // Change colors import stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors') diff --git a/src/util/getAllConfigs.js b/src/util/getAllConfigs.js index ce3665b97..90a20e11a 100644 --- a/src/util/getAllConfigs.js +++ b/src/util/getAllConfigs.js @@ -2,7 +2,14 @@ import defaultFullConfig from '../../stubs/config.full.js' import { flagEnabled } from '../featureFlags' export default function getAllConfigs(config) { - const configs = (config?.presets ?? [defaultFullConfig]) + const configs = ( + config?.presets ?? [ + __OXIDE__ + ? // Drop `content` in the oxide engine to promote auto content + Object.assign({}, defaultFullConfig, { content: 'auto' }) + : defaultFullConfig, + ] + ) .slice() .reverse() .flatMap((preset) => getAllConfigs(preset instanceof Function ? preset() : preset)) diff --git a/src/util/normalizeConfig.js b/src/util/normalizeConfig.js index 7e1a592de..a79aaefd0 100644 --- a/src/util/normalizeConfig.js +++ b/src/util/normalizeConfig.js @@ -18,6 +18,10 @@ export function normalizeConfig(config) { * } */ let valid = (() => { + if (config.content === 'auto') { + return true + } + // `config.purge` should not exist anymore if (config.purge) { return false @@ -181,6 +185,31 @@ export function normalizeConfig(config) { config.prefix = config.prefix ?? '' } + let auto = (() => { + // Config still has a `purge` option (for backwards compatibility), auto content should not be + // used + if (config.purge) return false + + // + if (config.content === 'auto') return true + + // We don't have content at all, auto content should be used + if (config.content === undefined) return true + + // We do have content as an object, but we don't have any files defined, auto content should + // be used + if ( + typeof config.content === 'object' && + config.content !== null && + !Array.isArray(config.content) + ) { + return config.content.files === undefined + } + + // We do have content defined, auto content should not be used + return false + })() + // Normalize the `content` config.content = { relative: (() => { @@ -193,17 +222,20 @@ export function normalizeConfig(config) { return flagEnabled(config, 'relativeContentPathsByDefault') })(), - files: (() => { - let { content, purge } = config + files: auto + ? 'auto' + : (() => { + let { content, purge } = config - if (Array.isArray(purge)) return purge - if (Array.isArray(purge?.content)) return purge.content - if (Array.isArray(content)) return content - if (Array.isArray(content?.content)) return content.content - if (Array.isArray(content?.files)) return content.files + if (content === undefined && purge === undefined) return [] + if (Array.isArray(purge)) return purge + if (Array.isArray(purge?.content)) return purge.content + if (Array.isArray(content)) return content + if (Array.isArray(content?.content)) return content.content + if (Array.isArray(content?.files)) return content.files - return [] - })(), + return [] + })(), extract: (() => { let extract = (() => { @@ -286,14 +318,16 @@ export function normalizeConfig(config) { // Validate globs to prevent bogus globs. // E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html` - for (let file of config.content.files) { - if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) { - log.warn('invalid-glob-braces', [ - `The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`, - `Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`, - // TODO: Add https://tw.wtf/invalid-glob-braces - ]) - break + if (config.content.files !== 'auto') { + for (let file of config.content.files) { + if (typeof file === 'string' && /{([^,]*?)}/g.test(file)) { + log.warn('invalid-glob-braces', [ + `The glob pattern ${dim(file)} in your Tailwind CSS configuration is invalid.`, + `Update it to ${dim(file.replace(/{([^,]*?)}/g, '$1'))} to silence this warning.`, + // TODO: Add https://tw.wtf/invalid-glob-braces + ]) + break + } } } diff --git a/src/util/validateConfig.js b/src/util/validateConfig.js index 8c22e4450..dfba01844 100644 --- a/src/util/validateConfig.js +++ b/src/util/validateConfig.js @@ -1,7 +1,7 @@ import log from './log' export function validateConfig(config) { - if (config.content.files.length === 0) { + if (config.content.files !== 'auto' && config.content.files.length === 0) { log.warn('content-problems', [ 'The `content` option in your Tailwind CSS configuration is missing or empty.', 'Configure your content sources or your generated CSS will be missing styles.', @@ -9,6 +9,13 @@ export function validateConfig(config) { ]) } + if (config.content.files === 'auto') { + log.warn('auto-content-experimental', [ + 'Automatic content detection in Tailwind CSS is currently in experimental preview.', + 'Preview features are not covered by semver, and may change at any time.', + ]) + } + // Warn if the line-clamp plugin is installed try { let plugin = require('@tailwindcss/line-clamp') diff --git a/tests/normalize-config.test.js b/tests/normalize-config.test.js index a0b7a59bb..47980cbdd 100644 --- a/tests/normalize-config.test.js +++ b/tests/normalize-config.test.js @@ -7,7 +7,7 @@ crosscheck(({ stable, oxide }) => { config ${{ purge: [{ raw: 'text-center' }] }} ${{ purge: { content: [{ raw: 'text-center' }] } }} - ${{ content: { content: [{ raw: 'text-center' }] } }} + ${{ content: { files: [], content: [{ raw: 'text-center' }] } }} `('should normalize content $config', ({ config }) => { return run('@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` @@ -22,7 +22,7 @@ crosscheck(({ stable, oxide }) => { config ${{ purge: { safelist: ['text-center'] } }} ${{ purge: { options: { safelist: ['text-center'] } } }} - ${{ content: { safelist: ['text-center'] } }} + ${{ content: { files: [], safelist: ['text-center'] } }} `('should normalize safelist $config', ({ config }) => { return run('@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` diff --git a/tests/warnings.test.js b/tests/warnings.test.js index e3ea94fe5..d2be7189f 100644 --- a/tests/warnings.test.js +++ b/tests/warnings.test.js @@ -1,7 +1,9 @@ import { crosscheck, run, html, css } from './util/run' -crosscheck(() => { - test('it warns when there is no content key', async () => { +crosscheck(({ oxide, stable }) => { + // The oxide engine will use auto content if no `content` is given + oxide.test.todo('it warns when there is no content key') + stable.test('it warns when there is no content key', async () => { let config = { corePlugins: { preflight: false }, } From 2f21b220498022aee00a71f30b1facbcc4cb7eca Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 12 May 2023 18:53:03 +0200 Subject: [PATCH 22/85] update CHANGELOG --- CHANGELOG.md | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7aa8bc7c..44a3c3c6c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,19 +17,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) - -### Changed - -- Reset padding for `` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) - -### Added - - [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) - Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205)) - [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173)) ### Changed +- Reset padding for `` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) - [Oxide] Disable color opacity plugins by default in the `oxide` engine ([#10618](https://github.com/tailwindlabs/tailwindcss/pull/10618)) - [Oxide] Enable relative content paths for the `oxide` engine ([#10621](https://github.com/tailwindlabs/tailwindcss/pull/10621)) From 764f6a19d4bf6e3cdf29e89bae09c6973dad9fb9 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 12 May 2023 19:35:23 +0200 Subject: [PATCH 23/85] add missing `^` to `package-lock.json` --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index af4967b34..4467139ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -104,7 +104,7 @@ "devDependencies": { "rollup": "^3.21.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "1.62.1" + "sass": "^1.62.1" } }, "integrations/tailwindcss-cli": { @@ -18936,7 +18936,7 @@ "requires": { "rollup": "^3.21.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "1.62.1" + "sass": "^1.62.1" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -29600,7 +29600,7 @@ "requires": { "rollup": "^3.21.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "1.62.1" + "sass": "^1.62.1" } }, "@tailwindcss/integrations-tailwindcss-cli": { From 0e171fd2ddf578cd8cb30b12c64c14146414797e Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Sat, 13 May 2023 00:15:30 +0200 Subject: [PATCH 24/85] [Oxide] Ensure generated `tailwind.config.js` file is formatted properly (#11221) * ensure beginning `\n` is not removed The `\s` regex includes newlines `\n`, but we only want leading spaces to be removed. * update changelog --- CHANGELOG.md | 2 +- src/cli/init/index.js | 2 +- src/oxide/cli/init/index.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 44a3c3c6c..69a7e2cb9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) - [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) - Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205)) -- [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173)) +- [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) ### Changed diff --git a/src/cli/init/index.js b/src/cli/init/index.js index ac118549a..b344b5b2e 100644 --- a/src/cli/init/index.js +++ b/src/cli/init/index.js @@ -40,7 +40,7 @@ export function init(args) { // Drop `content` in the oxide engine to promote auto content if (__OXIDE__) { - stubContentsFile = stubContentsFile.replace(/\s*content: \[\],\n/, '') + stubContentsFile = stubContentsFile.replace(/ *content: \[\],\n/, '') } // Change colors import diff --git a/src/oxide/cli/init/index.ts b/src/oxide/cli/init/index.ts index b05138349..ed69be95b 100644 --- a/src/oxide/cli/init/index.ts +++ b/src/oxide/cli/init/index.ts @@ -38,7 +38,7 @@ export function init(args) { // Drop `content` in the oxide engine to promote auto content if (__OXIDE__) { - stubContentsFile = stubContentsFile.replace(/\s*content: \[\],\n/, '') + stubContentsFile = stubContentsFile.replace(/ *content: \[\],\n/, '') } // Change colors import From f49b054b7df872bfaf0d08dfce82dcabc16e154f Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 15 May 2023 19:29:57 +0200 Subject: [PATCH 25/85] [Oxide] Add built-in `@import` processing support (#11239) * run PostCSS relative to test file The PostCSS `from` was always set to the `tests/util/run` file with the current test name as a query param to make it unique. However, that results in issues with relative file paths because they are now relative to this file instead of the actual test file. Luckily, `expect.getState()` exposes the `testPath` value that points to the current test file itself. * add built in `@import` processing + additional features such that you can use `@tailwind` and `@config` directives before the `@import` at rule which isn't normally allowed. However "@tailwind" in a way is an `@import` and `@config` in a way is a `@charset` which can be used before the `@import` at rule. * drop partial normalizeTailwindDirectives when in the Oxide engine This will now be handled by Tailwind from a higher level, so the core doesn't have to worry about normalizing this anymore since it will always be normalized right now. * add `handleImportAtRules` to CLI * update changelog * scope `import processing` to the oxide engine * update Changelog * use direct comparison We don't need the `startsWith` check anymore because the contents of the comment will be the actual value we expect. --- CHANGELOG.md | 3 +- src/lib/handleImportAtRules.js | 33 +++++++++++ src/lib/normalizeTailwindDirectives.js | 50 ++++++++-------- src/oxide/cli/build/plugin.ts | 38 ++----------- src/plugin.js | 2 + tests/import-processing-a.css | 1 + tests/import-processing-b.css | 5 ++ tests/import-processing-c.css | 5 ++ tests/import-processing-c.js | 9 +++ tests/import-processing.test.js | 79 ++++++++++++++++++++++++++ tests/util/run.js | 8 +-- 11 files changed, 170 insertions(+), 63 deletions(-) create mode 100644 src/lib/handleImportAtRules.js create mode 100644 tests/import-processing-a.css create mode 100644 tests/import-processing-b.css create mode 100644 tests/import-processing-c.css create mode 100644 tests/import-processing-c.js create mode 100644 tests/import-processing.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 69a7e2cb9..0b1c90fa7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,9 +17,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) -- [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) - Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205)) +- [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) - [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) +- [Oxide] Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) ### Changed diff --git a/src/lib/handleImportAtRules.js b/src/lib/handleImportAtRules.js new file mode 100644 index 000000000..57587d309 --- /dev/null +++ b/src/lib/handleImportAtRules.js @@ -0,0 +1,33 @@ +import postcss from 'postcss' + +const TAILWIND = Symbol() + +export function handleImportAtRules(postcssImport = require('postcss-import')) { + let RESTORE_ATRULE_COMMENT = '__TAILWIND_RESTORE__' + let atRulesToRestore = ['tailwind', 'config'] + + return [ + (root) => { + root.walkAtRules((rule) => { + if (!atRulesToRestore.includes(rule.name)) return rule + + rule.after( + postcss.comment({ + text: RESTORE_ATRULE_COMMENT, + raws: { [TAILWIND]: { rule } }, + }) + ) + rule.remove() + }) + }, + postcssImport(), + (root) => { + root.walkComments((rule) => { + if (rule.text === RESTORE_ATRULE_COMMENT) { + rule.after(rule.raws[TAILWIND].rule) + rule.remove() + } + }) + }, + ] +} diff --git a/src/lib/normalizeTailwindDirectives.js b/src/lib/normalizeTailwindDirectives.js index 3349a7e3a..530ff35b3 100644 --- a/src/lib/normalizeTailwindDirectives.js +++ b/src/lib/normalizeTailwindDirectives.js @@ -10,30 +10,32 @@ export default function normalizeTailwindDirectives(root) { applyDirectives.add(atRule) } - if (atRule.name === 'import') { - if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") { - atRule.name = 'tailwind' - atRule.params = 'base' - } else if ( - atRule.params === '"tailwindcss/components"' || - atRule.params === "'tailwindcss/components'" - ) { - atRule.name = 'tailwind' - atRule.params = 'components' - } else if ( - atRule.params === '"tailwindcss/utilities"' || - atRule.params === "'tailwindcss/utilities'" - ) { - atRule.name = 'tailwind' - atRule.params = 'utilities' - } else if ( - atRule.params === '"tailwindcss/screens"' || - atRule.params === "'tailwindcss/screens'" || - atRule.params === '"tailwindcss/variants"' || - atRule.params === "'tailwindcss/variants'" - ) { - atRule.name = 'tailwind' - atRule.params = 'variants' + if (!__OXIDE__) { + if (atRule.name === 'import') { + if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") { + atRule.name = 'tailwind' + atRule.params = 'base' + } else if ( + atRule.params === '"tailwindcss/components"' || + atRule.params === "'tailwindcss/components'" + ) { + atRule.name = 'tailwind' + atRule.params = 'components' + } else if ( + atRule.params === '"tailwindcss/utilities"' || + atRule.params === "'tailwindcss/utilities'" + ) { + atRule.name = 'tailwind' + atRule.params = 'utilities' + } else if ( + atRule.params === '"tailwindcss/screens"' || + atRule.params === "'tailwindcss/screens'" || + atRule.params === '"tailwindcss/variants"' || + atRule.params === "'tailwindcss/variants'" + ) { + atRule.name = 'tailwind' + atRule.params = 'variants' + } } } diff --git a/src/oxide/cli/build/plugin.ts b/src/oxide/cli/build/plugin.ts index aa9bb5b99..f6193b534 100644 --- a/src/oxide/cli/build/plugin.ts +++ b/src/oxide/cli/build/plugin.ts @@ -19,6 +19,7 @@ import { loadConfig } from '../../../lib/load-config' import getModuleDependencies from '../../../lib/getModuleDependencies' import type { Config } from '../../../../types' import { validateConfig } from '../../../util/validateConfig' +import { handleImportAtRules } from '../../../lib/handleImportAtRules' /** * @@ -75,39 +76,6 @@ async function loadPostCssPlugins(customPostCssPath) { return [beforePlugins, afterPlugins, config.options] } -function loadBuiltinPostcssPlugins() { - let postcss = loadPostcss() - let IMPORT_COMMENT = '__TAILWIND_RESTORE_IMPORT__: ' - return [ - [ - (root) => { - root.walkAtRules('import', (rule) => { - if (rule.params.slice(1).startsWith('tailwindcss/')) { - rule.after(postcss.comment({ text: IMPORT_COMMENT + rule.params })) - rule.remove() - } - }) - }, - loadPostcssImport(), - (root) => { - root.walkComments((rule) => { - if (rule.text.startsWith(IMPORT_COMMENT)) { - rule.after( - postcss.atRule({ - name: 'import', - params: rule.text.replace(IMPORT_COMMENT, ''), - }) - ) - rule.remove() - } - }) - }, - ], - [], - {}, - ] -} - let state = { /** @type {any} */ context: null, @@ -266,7 +234,9 @@ export async function createProcessor(args, cliConfigPath) { let [beforePlugins, afterPlugins, postcssOptions] = includePostCss ? await loadPostCssPlugins(customPostCssPath) - : loadBuiltinPostcssPlugins() + : [[], [], {}] + + beforePlugins.unshift(...handleImportAtRules(loadPostcssImport())) if (args['--purge']) { log.warn('purge-flag-deprecated', [ diff --git a/src/plugin.js b/src/plugin.js index 59f5fab01..86f39d962 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -2,6 +2,7 @@ import setupTrackingContext from './lib/setupTrackingContext' import processTailwindFeatures from './processTailwindFeatures' import { env } from './lib/sharedState' import { findAtConfigPath } from './lib/findAtConfigPath' +import { handleImportAtRules } from './lib/handleImportAtRules' module.exports = function tailwindcss(configOrPath) { return { @@ -13,6 +14,7 @@ module.exports = function tailwindcss(configOrPath) { console.time('JIT TOTAL') return root }, + ...(__OXIDE__ ? handleImportAtRules() : []), function (root, result) { // Use the path for the `@config` directive if it exists, otherwise use the // path for the file being processed diff --git a/tests/import-processing-a.css b/tests/import-processing-a.css new file mode 100644 index 000000000..65dd5f63a --- /dev/null +++ b/tests/import-processing-a.css @@ -0,0 +1 @@ +@tailwind utilities; diff --git a/tests/import-processing-b.css b/tests/import-processing-b.css new file mode 100644 index 000000000..69d5390f1 --- /dev/null +++ b/tests/import-processing-b.css @@ -0,0 +1,5 @@ +@layer utilities { + .foo { + color: red; + } +} diff --git a/tests/import-processing-c.css b/tests/import-processing-c.css new file mode 100644 index 000000000..508c10fe2 --- /dev/null +++ b/tests/import-processing-c.css @@ -0,0 +1,5 @@ +@tailwind utilities; + +.foo { + color: red; +} diff --git a/tests/import-processing-c.js b/tests/import-processing-c.js new file mode 100644 index 000000000..164503d5e --- /dev/null +++ b/tests/import-processing-c.js @@ -0,0 +1,9 @@ +module.exports = { + darkMode: 'class', + content: [ + { + raw: `
`, + }, + ], + corePlugins: { preflight: false }, +} diff --git a/tests/import-processing.test.js b/tests/import-processing.test.js new file mode 100644 index 000000000..962b7b28c --- /dev/null +++ b/tests/import-processing.test.js @@ -0,0 +1,79 @@ +import { html, css, run, crosscheck } from './util/run' + +crosscheck(({ oxide, stable }) => { + stable.test.todo('Import processing is an oxide engine feature') + oxide.describe('import processing', () => { + it('should be possible to import another css file', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @import './import-processing-a.css'; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + `) + }) + + it('should be possible to import another css file after @tailwind directive', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + @import './import-processing-b.css'; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + + .foo { + color: red; + } + `) + }) + + it('should be possible to add @config before @import statements', async () => { + let input = css` + @config "./import-processing-c.js"; + @import './import-processing-c.css'; + ` + + let result = await run(input) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + + .foo { + color: red; + } + `) + }) + }) +}) diff --git a/tests/util/run.js b/tests/util/run.js index 118edcb75..964d5d5f5 100644 --- a/tests/util/run.js +++ b/tests/util/run.js @@ -17,18 +17,18 @@ export let map = JSON.stringify({ globalThis.__OXIDE__ = env.ENGINE === 'oxide' export function run(input, config, plugin = tailwind) { - let { currentTestName } = expect.getState() + let { currentTestName, testPath } = expect.getState() return postcss(plugin(config)).process(input, { - from: `${path.resolve(__filename)}?test=${currentTestName}`, + from: `${path.resolve(testPath)}?test=${currentTestName}`, }) } export function runWithSourceMaps(input, config, plugin = tailwind) { - let { currentTestName } = expect.getState() + let { currentTestName, testPath } = expect.getState() return postcss(plugin(config)).process(input, { - from: `${path.resolve(__filename)}?test=${currentTestName}`, + from: `${path.resolve(testPath)}?test=${currentTestName}`, map: { prev: map, }, From 9ebaaaccb371784dbd157c6177433e4d6674a5f2 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 19 May 2023 18:13:02 +0200 Subject: [PATCH 26/85] Explicitly list published CSS files (#11260) * explicitly list all css files This also omits the oxide engine only `index.css` * update changelog --- CHANGELOG.md | 2 +- package.stable.json | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b1c90fa7..36ce4de0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) -- Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205)) +- [Oxide] Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205), ([#11260](https://github.com/tailwindlabs/tailwindcss/pull/11260))) - [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) - [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) - [Oxide] Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) diff --git a/package.stable.json b/package.stable.json index 6022310d8..0e83f619f 100644 --- a/package.stable.json +++ b/package.stable.json @@ -42,8 +42,13 @@ "nesting/*", "types/**/*", "*.d.ts", - "*.css", - "*.js" + "*.js", + "base.css", + "components.css", + "screens.css", + "tailwind.css", + "utilities.css", + "variants.css" ], "devDependencies": { "@swc/cli": "^0.1.62", From 0af64ee3e8b9f39e34f9174671faca5225fe0039 Mon Sep 17 00:00:00 2001 From: Daniel Kouznetsov Date: Mon, 22 May 2023 14:34:10 +0200 Subject: [PATCH 27/85] fixed a type in generateRules.js (#11264) --- src/lib/generateRules.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index 60da2323f..cbd671075 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -193,13 +193,13 @@ function applyVariant(variant, matches, context) { // group[:hover] (`-` is missing) let match = /(.)(-?)\[(.*)\]/g.exec(variant) if (match) { - let [, char, seperator, value] = match + let [, char, separator, value] = match // @-[200px] case - if (char === '@' && seperator === '-') return [] + if (char === '@' && separator === '-') return [] // group[:hover] case - if (char !== '@' && seperator === '') return [] + if (char !== '@' && separator === '') return [] - variant = variant.replace(`${seperator}[${value}]`, '') + variant = variant.replace(`${separator}[${value}]`, '') args.value = value } } From 581cf6abcca8b99498c93bf43f81435fa3dd5549 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 25 May 2023 04:10:00 +0200 Subject: [PATCH 28/85] Merge engines (#11275) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Simplify CI, make oxide engine the default (#11281) * remove integration tests for the `stable` engine * make `integration-tests-oxide` the default integration tests workflow * remove unnecessary CACHE_PREFIX * drop `ci-stable.yml` workflow * make `CI — Oxide` the default + drop testing against 3.3 branch (since this is stable only) + remove unnecessary CACHE_PREFIX * drop `release-insiders-stable.yml` workflow * make `Release Insiders — Oxide` the default + change release channel to just `insiders` instead of `oxide-insders` * drop 3.3 branch from integration tests * change job name for insiders release This makes it consistent with the other job names * prep `release-oxide.yml` workflow to be the default workflow * add Tailwind Play update Currently commented out until we figure out how this will work exactly. * use `env.VERSION` for the version we want to release * drop `release-stable.yml` workflow * make `release-oxide.yml` the default `release.yml` workflow * inline "Calculate environment variables" step * cache node_modules and cargo related files/folders in the release step * always use the default CLI * drop oxide specific implementation * ensure we test `--postcss` in the CLI Even for the Oxide engine * always process `@import` rules * remove `generalizedModifiers` flag This was already enabled by default. This commits removes some of the outstanding references to it. * remove built-in peer dependencies for the CLI * drop unused esbuild dependency * fix type for `configBag` * setup Lightning CSS for the CLI * drop `cssnano` dependency We only used this in the CLI and we now use Lighting CSS which has this built in already. Therefore we can get rid of this as a dependency. * ensure `imported.css` file exists in integration tests * passthrough `options` to lightningcss Ideally we can read this from `result.map` instead. However this doesn't get filled in for whatever reason even though we use `map: {inline:true}`. You can run the `tests/cli.test.js`, and more specifically the `--postcss supports process options with custom config` test. * Always process CSS with Lightning CSS Some tests temporarily skipped. Autoprefixer removed from `postcss.config.js` stubs since vendor prefixing handled by Lightning. * Remove code for normalizing `@import "tailwindcss/*"` statements * ensure tailwind doesn't crash when a `tailwind.config.js` file is not present * add `log.group` to group multiple messages together with different types * remove engine specific checks in integration tests * remove unused imports/variables Make linting check happy * support `content: ['auto']` This will allow us to still use auto content detection, but since this is part of the `content` array, it also allows you to add custom paths if you want. E.g.: ```js content: ['auto', './node_modules/my-library/*.{jsx,tsx}'] ``` * ensure `content.files` is always an array This allows us to simplify some checks because 'auto' will now be part of the array instead of checking if `content.files` is auto or if it is an array containing 'auto'. * fix tests, ensure default config is not injected * simplify `auto` normalization * always use the defaultFullConfig No need to override the defaultFullConfig with `{content: 'auto'}` because this will be included in the default config already. * drop condition which ensured `files` was an empty array This is not needed anymore because when `content` is omitted it behaves as if it was set to `auto`. * drop removal of `content` We used to remove the `content` from the actual configuration files when using `tailwindcss init` for the oxide engine. This was to ensure that `auto content detection` was used instead (by default). But now it is always enabled by default therefore this is not needed anymore. * ensure setting `content: 'auto'` works * improve file cache handling We have to make sure that we get into the previous state whenver a test is done. We were using some `!fileCache[filePath]` checks, however we also used `null` as a sentinel value when something wasn't found. But, `null` is falsey as well so some checks where incorrect. Using a dedicated value and a `Map` makes this safer and more correct because we can now use `.has()`. * drop `cleanupFile`, `removeFile` will already take care of it * drop oxide check in `resolvedChangedContent` At this point the `context.tailwindConfig.content.files` is already fully resolved regardless of the engine we are in. * refactor `parseCandidateStringsFromFiles` strategy, to make use of a proper feature flag * use feature flag for sorting classes Once the Oxide engine is the default default, then we can drop this entirely because the result from the Rust parser will already be sorted. * drop `crosscheck` from tests where it is safe First pass of deleting `crosscheck`. These are all the places where we didn't have any differences between the Oxide and Stable engine. * replace `__OXIDE__` in corePlugins with feature flag * use `globalThis.__OXIDE__ ?? false` This will ensure that in places where we don't have `__OXIDE__` that we can still properly fallback to `false`. * use `flex` as the go-to utility when testing features * prefer `space-utilities` tests instead of `oxide` test * drop crosscheck check Since the `oxideParser` is disabled by default, all the tests can use the `stable` output. * use simple `false` default values for feature flag defaults * drop `__OXIDE__` injections in build scripts * use stable `flex` and `z-{...}` utilities instead of color utilities flex and z-index related utilities are more stable than the color utilities right now because the color utilities will use a raw color value or a combination with a css variable depending on a feature flag. * drop unused `ENGINE` environment variable * drop stable engine manifest files * drop `swap-engines` tooling --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com> --- .github/workflows/ci-stable.yml | 59 - .github/workflows/ci.yml | 9 +- .../workflows/integration-tests-stable.yml | 83 - ...-tests-oxide.yml => integration-tests.yml} | 9 +- .github/workflows/release-insiders-stable.yml | 78 - ...nsiders-oxide.yml => release-insiders.yml} | 6 +- .github/workflows/release-stable.yml | 68 - .../{release-oxide.yml => release.yml} | 263 +- integrations/io.js | 28 +- integrations/parcel/tests/integration.test.js | 205 +- .../postcss-cli/tests/integration.test.js | 138 +- .../rollup-sass/tests/integration.test.js | 183 +- integrations/rollup/tests/integration.test.js | 208 +- .../tailwindcss-cli/tests/cli.test.js | 184 +- .../tailwindcss-cli/tests/integration.test.js | 1441 +- integrations/vite/tests/integration.test.js | 214 +- .../webpack-4/tests/integration.test.js | 208 +- .../webpack-5/tests/integration.test.js | 258 +- package-lock.json | 272 +- package-lock.stable.json | 13997 ---------------- package.json | 11 +- package.stable.json | 126 - scripts/swap-engines.js | 40 - src/cli-peer-dependencies.js | 15 - src/cli.js | 6 +- src/cli/build/deps.js | 56 - src/cli/build/plugin.js | 102 +- src/cli/init/index.js | 5 - src/corePlugins.js | 8 +- src/featureFlags.js | 14 +- src/lib/content.js | 37 +- src/lib/expandTailwindAtRules.js | 8 +- src/lib/generateRules.js | 4 - src/lib/handleImportAtRules.js | 3 +- src/lib/normalizeTailwindDirectives.js | 29 - src/lib/setupContextUtils.js | 18 +- src/lib/setupTrackingContext.js | 4 +- src/lib/sharedState.js | 4 - src/oxide/cli.ts | 1 - src/oxide/cli/build/deps.ts | 91 - src/oxide/cli/build/index.ts | 47 - src/oxide/cli/build/plugin.ts | 419 - src/oxide/cli/build/utils.ts | 74 - src/oxide/cli/build/watching.ts | 225 - src/oxide/cli/help/index.ts | 69 - src/oxide/cli/index.ts | 204 - src/oxide/cli/init/index.ts | 64 - src/oxide/postcss-plugin.ts | 1 - src/plugin.js | 112 +- src/util/getAllConfigs.js | 9 +- src/util/log.js | 24 + src/util/normalizeConfig.js | 52 +- src/util/pluginUtils.js | 4 - src/util/validateConfig.js | 15 +- stubs/config.full.js | 2 +- stubs/config.simple.js | 2 +- stubs/postcss.config.cjs | 1 - stubs/postcss.config.js | 1 - tests/animations.test.js | 536 +- tests/any-type.test.js | 2057 +-- tests/apply.test.js | 4057 ++--- tests/arbitrary-properties.test.js | 906 +- tests/arbitrary-values.oxide.test.css | 1073 -- tests/arbitrary-values.test.css | 2 +- tests/arbitrary-values.test.js | 1169 +- tests/arbitrary-variants.test.js | 2070 ++- tests/basic-usage.oxide.test.css | 1028 -- tests/basic-usage.test.js | 1904 +-- tests/blocklist.test.js | 211 +- tests/collapse-adjacent-rules.test.js | 350 +- tests/collapse-duplicate-declarations.test.js | 334 +- tests/color-opacity-modifiers.test.js | 490 +- tests/color.test.js | 177 +- tests/combined-selectors.test.js | 130 +- tests/configurePlugins.test.js | 43 +- tests/containerPlugin.test.js | 664 +- tests/context-reuse.test.js | 202 +- tests/custom-extractors.test.js | 192 +- tests/custom-plugins.test.js | 3703 ++-- tests/custom-separator.test.js | 98 +- tests/custom-transformers.test.js | 123 +- tests/customConfig.test.js | 720 +- tests/dark-mode.test.js | 234 +- tests/detect-nesting.test.js | 210 +- tests/escapeClassName.test.js | 7 +- tests/evaluateTailwindFunctions.test.js | 2639 ++- tests/experimental.test.js | 382 +- tests/extractor-edge-cases.test.js | 58 +- tests/flattenColorPalette.test.js | 153 +- tests/format-variant-selector.test.js | 633 +- tests/generate-rules.test.js | 78 +- tests/getClassList.test.js | 377 +- tests/getSortOrder.test.js | 195 +- tests/getVariants.test.js | 317 +- tests/import-processing.test.js | 135 +- tests/import-syntax.test.js | 185 +- tests/important-boolean.test.js | 406 +- tests/important-modifier-prefix.test.js | 130 +- tests/important-modifier.test.js | 274 +- tests/important-selector.test.js | 362 +- tests/kitchen-sink.test.js | 1994 +-- tests/layer-at-rules.test.js | 546 +- tests/layer-without-tailwind.test.js | 126 +- tests/match-components.test.js | 152 +- tests/match-utilities.test.js | 1126 +- tests/match-variants.test.js | 1524 +- tests/min-max-screen-variants.test.js | 1186 +- tests/minimum-impact-selector.test.js | 55 +- tests/modify-selectors.test.js | 158 +- tests/mutable.test.js | 84 +- tests/negateValue.test.js | 25 +- tests/negated-content.test.js | 44 +- tests/negative-prefix.test.js | 678 +- tests/normalize-config.test.js | 309 +- tests/normalize-data-types.test.js | 7 +- tests/normalize-screens.test.js | 121 +- tests/opacity.test.js | 2144 ++- tests/oxide.test.js | 22 - tests/parallel-variants.test.js | 266 +- tests/parseAnimationValue.test.js | 387 +- tests/parseObjectStyles.test.js | 556 +- tests/plugins/divide.test.js | 183 +- tests/plugins/fontFamily.test.js | 156 +- tests/plugins/fontSize.test.js | 382 +- tests/plugins/gradientColorStops.test.js | 330 +- tests/prefers-contrast.test.js | 157 +- tests/prefix.test.js | 1180 +- tests/prefixSelector.test.js | 31 +- tests/preflight.test.js | 38 +- tests/raw-content.oxide.test.css | 759 - tests/raw-content.test.js | 323 +- tests/relative-purge-paths.test.js | 36 +- tests/resolve-defaults-at-rules.test.js | 1469 +- tests/resolveConfig.test.js | 3153 ++-- tests/responsive-and-variants-atrules.test.js | 264 +- tests/safelist.test.js | 1119 +- tests/screenAtRule.test.js | 76 +- tests/shared-state.test.js | 37 +- tests/source-maps.test.js | 1045 +- tests/space-utilities.test.js | 43 + tests/syntax-lit-html.test.js | 109 +- tests/syntax-svelte.test.js | 106 +- tests/tailwind-screens.test.js | 110 +- tests/to-path.test.js | 31 +- tests/util/apply-important-selector.test.js | 39 +- tests/util/crosscheck.test.js | 18 - tests/util/run.js | 61 - tests/variants.oxide.test.css | 412 - tests/variants.test.css | 487 +- tests/variants.test.html | 274 +- tests/variants.test.js | 2067 ++- tests/warnings.test.js | 115 +- tests/withAlphaVariable.test.js | 471 +- turbo.json | 2 +- 154 files changed, 26652 insertions(+), 48773 deletions(-) delete mode 100644 .github/workflows/ci-stable.yml delete mode 100644 .github/workflows/integration-tests-stable.yml rename .github/workflows/{integration-tests-oxide.yml => integration-tests.yml} (89%) delete mode 100644 .github/workflows/release-insiders-stable.yml rename .github/workflows/{release-insiders-oxide.yml => release-insiders.yml} (99%) delete mode 100644 .github/workflows/release-stable.yml rename .github/workflows/{release-oxide.yml => release.yml} (52%) delete mode 100644 package-lock.stable.json delete mode 100644 package.stable.json delete mode 100644 scripts/swap-engines.js delete mode 100644 src/cli-peer-dependencies.js delete mode 100644 src/cli/build/deps.js delete mode 100644 src/oxide/cli.ts delete mode 100644 src/oxide/cli/build/deps.ts delete mode 100644 src/oxide/cli/build/index.ts delete mode 100644 src/oxide/cli/build/plugin.ts delete mode 100644 src/oxide/cli/build/utils.ts delete mode 100644 src/oxide/cli/build/watching.ts delete mode 100644 src/oxide/cli/help/index.ts delete mode 100644 src/oxide/cli/index.ts delete mode 100644 src/oxide/cli/init/index.ts delete mode 100644 src/oxide/postcss-plugin.ts delete mode 100644 tests/arbitrary-values.oxide.test.css delete mode 100644 tests/basic-usage.oxide.test.css delete mode 100644 tests/oxide.test.js delete mode 100644 tests/raw-content.oxide.test.css create mode 100644 tests/space-utilities.test.js delete mode 100644 tests/util/crosscheck.test.js delete mode 100644 tests/variants.oxide.test.css diff --git a/.github/workflows/ci-stable.yml b/.github/workflows/ci-stable.yml deleted file mode 100644 index 80d19dca0..000000000 --- a/.github/workflows/ci-stable.yml +++ /dev/null @@ -1,59 +0,0 @@ -# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node -# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions - -name: CI — Stable - -on: - push: - branches: [master] - pull_request: - branches: [master, 3.3] - -permissions: - contents: read - -env: - CI: true - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: stable - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14, 18] - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Cache node_modules - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} - - - name: Install dependencies - run: npm install - - - name: Build Tailwind CSS - run: npm run build - - - name: Test - run: | - npm run test || \ - npm run test || \ - npm run test || exit 1 - - - name: Lint - run: npm run style diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b7e4a4674..5488096e3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,10 +1,10 @@ -name: CI — Oxide +name: CI on: push: - branches: [master, 3.3] + branches: [master] pull_request: - branches: [master, 3.3] + branches: [master] permissions: contents: read @@ -13,7 +13,6 @@ env: CI: true TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: oxide jobs: build: @@ -34,7 +33,7 @@ jobs: uses: actions/cache@v3 with: path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-${{ matrix.node-version }}-node_modules-${{ hashFiles('**/package-lock.json') }} # Cargo already skips downloading dependencies if they already exist - name: Cache cargo diff --git a/.github/workflows/integration-tests-stable.yml b/.github/workflows/integration-tests-stable.yml deleted file mode 100644 index b28207196..000000000 --- a/.github/workflows/integration-tests-stable.yml +++ /dev/null @@ -1,83 +0,0 @@ -name: Integration Tests — Stable - -on: - push: - branches: [master, 3.3] - pull_request: - branches: [master, 3.3] - -permissions: - contents: read - -env: - CI: true - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: stable - -jobs: - test: - runs-on: ubuntu-latest - - strategy: - matrix: - integration: - - content-resolution - - parcel - - postcss-cli - - rollup - - rollup-sass - - tailwindcss-cli - - vite - - webpack-4 - - webpack-5 - node-version: [18] - fail-fast: false - - steps: - - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Cache node_modules (tailwindcss) - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('package-lock.json') }} - - - name: Cache node_modules (integrations) - uses: actions/cache@v3 - with: - path: ./integrations/node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-integrations-${{ hashFiles('./integrations/package-lock.json') }} - - - name: Cache node_modules (integration) - uses: actions/cache@v3 - with: - path: ./integrations/${{ matrix.integration }}/node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-integrations-${{ matrix.integration }}-${{ hashFiles('./integrations/${{ matrix.integration }}/package-lock.json') }} - - - name: Install dependencies - run: npm install - - - name: Install dependencies (shared integrations) - run: npm install --prefix ./integrations - - - name: Install dependencies (integration) - run: npm install --prefix ./integrations/${{ matrix.integration }} - - - name: Build Tailwind CSS - run: npm run build - - - name: Test ${{ matrix.integration }} - run: | - npm run test --prefix ./integrations/${{ matrix.integration }} || \ - npm run test --prefix ./integrations/${{ matrix.integration }} || \ - npm run test --prefix ./integrations/${{ matrix.integration }} || exit 1 diff --git a/.github/workflows/integration-tests-oxide.yml b/.github/workflows/integration-tests.yml similarity index 89% rename from .github/workflows/integration-tests-oxide.yml rename to .github/workflows/integration-tests.yml index 9da82b4b8..722a08ad3 100644 --- a/.github/workflows/integration-tests-oxide.yml +++ b/.github/workflows/integration-tests.yml @@ -1,10 +1,10 @@ -name: Integration Tests — Oxide +name: Integration Tests on: push: - branches: [master, 3.3] + branches: [master] pull_request: - branches: [master, 3.3] + branches: [master] permissions: contents: read @@ -13,7 +13,6 @@ env: CI: true TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: oxide jobs: test: @@ -46,7 +45,7 @@ jobs: uses: actions/cache@v3 with: path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-${{ matrix.node-version }}-node_modules-${{ hashFiles('**/package-lock.json') }} # Cargo already skips downloading dependencies if they already exist - name: Cache cargo diff --git a/.github/workflows/release-insiders-stable.yml b/.github/workflows/release-insiders-stable.yml deleted file mode 100644 index f8bb322d4..000000000 --- a/.github/workflows/release-insiders-stable.yml +++ /dev/null @@ -1,78 +0,0 @@ -name: Release Insiders — Stable - -on: - push: - branches: [master] - -permissions: - contents: read - -env: - CI: true - TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} - TURBO_TEAM: ${{ secrets.TURBO_TEAM }} - CACHE_PREFIX: stable - NODE_VERSION: 16 - RELEASE_CHANNEL: insiders - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v3 - with: - node-version: ${{ env.NODE_VERSION }} - registry-url: 'https://registry.npmjs.org' - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Cache node_modules - uses: actions/cache@v3 - with: - path: node_modules - key: ${{ runner.os }}-${{ env.NODE_VERSION }}-${{ env.CACHE_PREFIX }}-node_modules-${{ hashFiles('**/package-lock.json') }} - - - name: Install dependencies - run: npm install - - - name: Build Tailwind CSS - run: npm run build - - - name: Test - run: | - npm run test || \ - npm run test || \ - npm run test || exit 1 - - - name: Resolve version - id: vars - run: | - echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - - name: 'Version based on commit: 0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }}' - run: npm version 0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }} --force --no-git-tag-version - - - name: Publish - run: npm publish --tag ${{ env.RELEASE_CHANNEL }} - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Trigger Tailwind Play update - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} - script: | - await github.rest.actions.createWorkflowDispatch({ - owner: 'tailwindlabs', - repo: 'play.tailwindcss.com', - ref: 'master', - workflow_id: 'upgrade-tailwindcss.yml', - inputs: { - insidersVersion: '0.0.0-${{ env.RELEASE_CHANNEL }}.${{ env.SHA_SHORT }}' - } - }) diff --git a/.github/workflows/release-insiders-oxide.yml b/.github/workflows/release-insiders.yml similarity index 99% rename from .github/workflows/release-insiders-oxide.yml rename to .github/workflows/release-insiders.yml index e074d064d..26e1b1167 100644 --- a/.github/workflows/release-insiders-oxide.yml +++ b/.github/workflows/release-insiders.yml @@ -1,4 +1,4 @@ -name: Release Insiders — Oxide +name: Release Insiders on: push: @@ -8,7 +8,7 @@ env: APP_NAME: tailwindcss-oxide NODE_VERSION: 16 OXIDE_LOCATION: ./oxide/crates/node - RELEASE_CHANNEL: oxide-insiders + RELEASE_CHANNEL: insiders jobs: build: @@ -353,7 +353,7 @@ jobs: env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - tailwind_oxide_release: + tailwind-release: runs-on: ubuntu-latest name: Build and release Tailwind CSS diff --git a/.github/workflows/release-stable.yml b/.github/workflows/release-stable.yml deleted file mode 100644 index 23a3f2dc0..000000000 --- a/.github/workflows/release-stable.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: Release — Stable - -on: - release: - types: [published] - -permissions: - contents: read - -env: - CI: true - -jobs: - build: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14] - - steps: - - uses: actions/checkout@v3 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - registry-url: 'https://registry.npmjs.org' - cache: 'npm' - - - name: Use the `stable` engine - run: | - node ./scripts/swap-engines.js - - - name: Install dependencies - run: npm install - - - name: Build Tailwind CSS - run: npm run build - - - name: Test - run: npm run test - - - name: Calculate environment variables - run: | - echo "RELEASE_CHANNEL=$(node ./scripts/release-channel.js)" >> $GITHUB_ENV - echo "TAILWINDCSS_VERSION=$(node -e 'console.log(require(`./package.json`).version);')" >> $GITHUB_ENV - - - name: Publish - run: npm publish --tag ${{ env.RELEASE_CHANNEL }} - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Trigger Tailwind Play update - if: env.RELEASE_CHANNEL == 'latest' - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} - script: | - await github.rest.actions.createWorkflowDispatch({ - owner: 'tailwindlabs', - repo: 'play.tailwindcss.com', - ref: 'master', - workflow_id: 'upgrade-tailwindcss.yml', - inputs: { - version: '${{ env.TAILWINDCSS_VERSION }}' - } - }) diff --git a/.github/workflows/release-oxide.yml b/.github/workflows/release.yml similarity index 52% rename from .github/workflows/release-oxide.yml rename to .github/workflows/release.yml index ad71ec657..3a1ab964d 100644 --- a/.github/workflows/release-oxide.yml +++ b/.github/workflows/release.yml @@ -1,15 +1,19 @@ -name: Release — Oxide +name: Release on: - workflow_dispatch: + release: + types: [published] + +permissions: + contents: read env: APP_NAME: tailwindcss-oxide - NODE_VERSION: 14 + NODE_VERSION: 16 OXIDE_LOCATION: ./oxide/crates/node jobs: - oxide-build: + build: strategy: fail-fast: false matrix: @@ -27,6 +31,35 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} + + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + - name: Install Node.JS uses: actions/setup-node@v3 with: @@ -42,18 +75,8 @@ jobs: - name: Setup rust target run: rustup target add ${{ matrix.target }} - # - name: Use cached oxide node_modules - # id: cache-oxide - # uses: actions/cache@v3 - # with: - # path: ${{ env.OXIDE_LOCATION }}/node_modules - # key: nodeModules-${{ hashFiles('${{ env.OXIDE_LOCATION }}/package-lock.json') }}-${{ matrix.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }} - # restore-keys: | - # nodeModules- - - - name: Oxide — npm install - # if: steps.cache-oxide.outputs.cache-hit != 'true' - run: cd ${{ env.OXIDE_LOCATION }} && npm install + - name: Install dependencies + run: npm install - name: Build release run: cd ${{ env.OXIDE_LOCATION }} && npm run build @@ -72,7 +95,7 @@ jobs: ${{ env.OXIDE_LOCATION }}/*.node ${{ matrix.binary }} - oxide-build-apple-silicon: + build-apple-silicon: name: Build Apple Silicon (OXIDE) runs-on: macos-latest steps: @@ -82,7 +105,7 @@ jobs: uses: actions/cache@v3 with: path: node_modules - key: ${{ runner.os }}-${{ matrix.node-version }}-node_modules-${{ hashFiles('**/package-lock.json') }} + key: ${{ runner.os }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} # Cargo already skips downloading dependencies if they already exist - name: Cache cargo @@ -94,7 +117,18 @@ jobs: ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ - key: ${{ runner.os }}-cargo-${{ hashFiles('./oxide/**/Cargo.lock') }} + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} - name: Install Node.JS uses: actions/setup-node@v3 @@ -131,7 +165,7 @@ jobs: ${{ env.OXIDE_LOCATION }}/*.node ${{ env.APP_NAME }} - oxide-build-linux: + build-linux: strategy: fail-fast: false matrix: @@ -162,6 +196,35 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} + + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + - name: Install Node.JS uses: actions/setup-node@v3 with: @@ -181,18 +244,8 @@ jobs: - name: Setup rust target run: rustup target add ${{ matrix.target }} - # - name: Use cached oxide node_modules - # id: cache-oxide - # uses: actions/cache@v3 - # with: - # path: ${{ env.OXIDE_LOCATION }}/node_modules - # key: nodeModules-${{ hashFiles('${{ env.OXIDE_LOCATION }}/package-lock.json') }}-linux-${{ matrix.target }}-${{ env.NODE_VERSION }} - # restore-keys: | - # nodeModules- - - - name: Oxide — npm install - # if: steps.cache-oxide.outputs.cache-hit != 'true' - run: cd ${{ env.OXIDE_LOCATION }} && npm install + - name: Install dependencies + run: npm install - name: Build release run: cd ${{ env.OXIDE_LOCATION }} && npm run build @@ -211,28 +264,52 @@ jobs: ${{ env.OXIDE_LOCATION }}/*.node ${{ env.APP_NAME }} - oxide-release: + release: runs-on: ubuntu-latest name: Build and release needs: - - oxide-build - - oxide-build-linux - - oxide-build-apple-silicon + - build + - build-linux + - build-apple-silicon steps: - uses: actions/checkout@v3 - # - name: Use cached oxide node_modules - # id: cache-oxide - # uses: actions/cache@v3 - # with: - # path: ${{ env.OXIDE_LOCATION }}/node_modules - # key: nodeModules-${{ hashFiles('${{ env.OXIDE_LOCATION }}/package-lock.json') }}-ubuntu-latest-${{ env.NODE_VERSION }} - # restore-keys: | - # nodeModules- + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} - - name: Oxide — npm install - # if: steps.cache-oxide.outputs.cache-hit != 'true' - run: cd ${{ env.OXIDE_LOCATION }} && npm install + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + + - name: Install dependencies + run: npm install + + - name: Calculate environment variables + run: | + echo "RELEASE_CHANNEL=$(node ./scripts/release-channel.js)" >> $GITHUB_ENV + echo "VERSION=$(node -e 'console.log(require(`./package.json`).version);')" >> $GITHUB_ENV - name: Download artifacts uses: actions/download-artifact@v3 @@ -255,11 +332,6 @@ jobs: cp bindings-x86_64-unknown-linux-gnu/oxide/crates/node/* ./npm/linux-x64-gnu/ cp bindings-x86_64-unknown-linux-musl/oxide/crates/node/* ./npm/linux-x64-musl/ - - name: Resolve version - id: vars - run: | - echo "NPM_VERSION=0.0.0-insiders.$(git rev-parse --short HEAD)" >> $GITHUB_ENV - - name: Generate entry point run: npm run build --prefix ${{ env.OXIDE_LOCATION }} @@ -268,50 +340,74 @@ jobs: for pkg in ${{ env.OXIDE_LOCATION }}/npm/*; do echo "Publishing $pkg..." cd $pkg - npm version ${{ env.NPM_VERSION }} --force --no-git-tag-version - npm publish --tag insiders --access public + npm version ${{ env.VERSION }} --force --no-git-tag-version + npm publish --tag ${{ env.RELEASE_CHANNEL }} --access public cd - done echo "Publishing ${{ env.APP_NAME }}..."; cd ${{ env.OXIDE_LOCATION }} - npm version ${{ env.NPM_VERSION }} --force --no-git-tag-version - sed "s#\"0.0.0\"#\"${{ env.NPM_VERSION }}\"#g" package.json > package_updated.json + npm version ${{ env.VERSION }} --force --no-git-tag-version + sed "s#\"0.0.0\"#\"${{ env.VERSION }}\"#g" package.json > package_updated.json mv package_updated.json package.json - npm publish --tag insiders --access public + npm publish --tag ${{ env.RELEASE_CHANNEL }} --access public cd - env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - tailwind_oxide_release: + tailwind-release: runs-on: ubuntu-latest name: Build and release Tailwind CSS needs: - - oxide-release - - strategy: - matrix: - node-version: [14] + - release steps: - uses: actions/checkout@v3 - - name: Use Node.js ${{ matrix.node-version }} + - name: Cache node_modules + uses: actions/cache@v3 + with: + path: node_modules + key: ${{ runner.os }}-${{ matrix.target }}-${{ env.NODE_VERSION }}-node_modules-${{ hashFiles('**/package-lock.json') }} + + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v3 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} + + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v3 + with: + path: | + ./oxide/target/ + ./oxide/crates/node/*.node + ./oxide/crates/node/index.js + ./oxide/crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./oxide/crates/**/*') }} + + - name: Use Node.js ${{ env.NODE_VERSION }} uses: actions/setup-node@v3 with: - node-version: ${{ matrix.node-version }} + node-version: ${{ env.NODE_VERSION }} registry-url: 'https://registry.npmjs.org' - - name: Resolve version - id: vars + - name: Calculate environment variables run: | - echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> $GITHUB_ENV - echo "OXIDE_NPM_VERSION=0.0.0-insiders.$(git rev-parse --short HEAD)" >> $GITHUB_ENV + echo "RELEASE_CHANNEL=$(node ./scripts/release-channel.js)" >> $GITHUB_ENV + echo "VERSION=$(node -e 'console.log(require(`./package.json`).version);')" >> $GITHUB_ENV - name: Setup `@tailwindcss/oxide` version run: | - sed "s#\"@tailwindcss/oxide\": \".*\"#\"@tailwindcss/oxide\": \"${{ env.OXIDE_NPM_VERSION }}\"#" package.json > package_updated.json + sed "s#\"@tailwindcss/oxide\": \".*\"#\"@tailwindcss/oxide\": \"${{ env.VERSION }}\"#" package.json > package_updated.json mv package_updated.json package.json - name: Install dependencies @@ -321,12 +417,31 @@ jobs: run: npm run build - name: Test - run: npm test + run: | + npm test || \ + npm test || \ + npm test || exit 1 - - name: 'Version based on commit: 0.0.0-oxide.${{ env.SHA_SHORT }}' - run: npm version 0.0.0-oxide.${{ env.SHA_SHORT }} --force --no-git-tag-version + - name: 'Version: ${{ env.VERSION }}' + run: npm version ${{ env.VERSION }} --force --no-git-tag-version - name: Publish - run: npm publish --tag oxide + run: npm publish --tag ${{ env.RELEASE_CHANNEL }} env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + # - name: Trigger Tailwind Play update + # if: env.RELEASE_CHANNEL == 'latest' + # uses: actions/github-script@v6 + # with: + # github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} + # script: | + # await github.rest.actions.createWorkflowDispatch({ + # owner: 'tailwindlabs', + # repo: 'play.tailwindcss.com', + # ref: 'master', + # workflow_id: 'upgrade-tailwindcss.yml', + # inputs: { + # version: '${{ env.TAILWINDCSS_VERSION }}' + # } + # }) diff --git a/integrations/io.js b/integrations/io.js index d30570d3a..0716aac7e 100644 --- a/integrations/io.js +++ b/integrations/io.js @@ -5,6 +5,9 @@ let fs = require('fs/promises') let chokidar = require('chokidar') let resolveToolRoot = require('./resolve-tool-root') +let FILE_STATE = { + NotFound: Symbol(), +} function getWatcherOptions() { return { @@ -28,7 +31,7 @@ module.exports = function ({ cleanup = true, } = {}) { let toolRoot = resolveToolRoot() - let fileCache = {} + let fileCache = new Map() let absoluteOutputFolder = path.resolve(toolRoot, output) let absoluteInputFolder = path.resolve(toolRoot, input) @@ -41,9 +44,9 @@ module.exports = function ({ // Restore all written files afterEach(async () => { await Promise.all( - Object.entries(fileCache).map(async ([file, content]) => { + Array.from(fileCache.entries()).map(async ([file, content]) => { try { - if (content === null) { + if (content === FILE_STATE.NotFound) { return await fs.unlink(file) } else { return await fs.writeFile(file, content, 'utf8') @@ -89,7 +92,7 @@ module.exports = function ({ return { cleanupFile(file) { let filePath = path.resolve(toolRoot, file) - fileCache[filePath] = null + fileCache.set(filePath, FILE_STATE.NotFound) }, async fileExists(file) { let filePath = path.resolve(toolRoot, file) @@ -98,8 +101,11 @@ module.exports = function ({ async removeFile(file) { let filePath = path.resolve(toolRoot, file) - if (!fileCache[filePath]) { - fileCache[filePath] = await fs.readFile(filePath, 'utf8').catch(() => null) + if (!fileCache.has(filePath)) { + fileCache.set( + filePath, + await fs.readFile(filePath, 'utf8').catch(() => FILE_STATE.NotFound) + ) } await fs.unlink(filePath).catch(() => null) @@ -114,8 +120,8 @@ module.exports = function ({ }, async appendToInputFile(file, contents) { let filePath = path.resolve(absoluteInputFolder, file) - if (!fileCache[filePath]) { - fileCache[filePath] = await fs.readFile(filePath, 'utf8') + if (!fileCache.has(filePath)) { + fileCache.set(filePath, await fs.readFile(filePath, 'utf8')) } return fs.appendFile(filePath, contents, 'utf8') @@ -133,12 +139,12 @@ module.exports = function ({ await fs.mkdir(path.dirname(filePath), { recursive: true }) } - if (!fileCache[filePath]) { + if (!fileCache.has(filePath)) { try { - fileCache[filePath] = await fs.readFile(filePath, 'utf8') + fileCache.set(filePath, await fs.readFile(filePath, 'utf8')) } catch (err) { if (err.code === 'ENOENT') { - fileCache[filePath] = null // Sentinel value to `delete` the file afterwards. This also means that we are writing to a `new` file inside the test. + fileCache.set(filePath, FILE_STATE.NotFound) } else { throw err } diff --git a/integrations/parcel/tests/integration.test.js b/integrations/parcel/tests/integration.test.js index b86af727e..15b007ac9 100644 --- a/integrations/parcel/tests/integration.test.js +++ b/integrations/parcel/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { appendToInputFile, @@ -40,7 +39,7 @@ describe('static build', () => { 'index.html', html` -
+
` ) await writeInputFile( @@ -58,8 +57,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -74,26 +73,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { @@ -102,7 +88,7 @@ describe('static build', () => { 'index.html', html` -
+
` ) await writeInputFile( @@ -122,8 +108,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -138,26 +124,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -199,41 +172,22 @@ describe('watcher', () => { ) await waitForOutputFileChange(/index\.\w+\.css$/, async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -271,41 +225,22 @@ describe('watcher', () => { ) await waitForOutputFileChange(/index\.\w+\.css$/, async () => { - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -438,43 +373,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .btn { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/postcss-cli/tests/integration.test.js b/integrations/postcss-cli/tests/integration.test.js index 46f5a61a6..cd8d2a904 100644 --- a/integrations/postcss-cli/tests/integration.test.js +++ b/integrations/postcss-cli/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile } = require('../../io')({ output: 'dist', @@ -58,41 +57,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -125,41 +105,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -277,47 +238,26 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { + expect(await readOutputFile('main.css')).toIncludeCss( + css` + /* prettier-ignore */ + .btn { border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - /* prettier-ignore */ - .btn { - border-radius: 0.25rem; - background-color: #ef4444; + z-index: 0; padding: 0.25rem 0.5rem; } - .font-bold { - font-weight: 700; - } - ` - ) - } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/rollup-sass/tests/integration.test.js b/integrations/rollup-sass/tests/integration.test.js index 19a769565..90a3831ff 100644 --- a/integrations/rollup-sass/tests/integration.test.js +++ b/integrations/rollup-sass/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile } = require('../../io')({ output: 'dist', @@ -58,41 +57,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -125,41 +105,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -275,43 +236,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) @@ -370,43 +313,25 @@ describe('watcher', () => { css` @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/rollup/tests/integration.test.js b/integrations/rollup/tests/integration.test.js index c3209af65..970d985f8 100644 --- a/integrations/rollup/tests/integration.test.js +++ b/integrations/rollup/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile, removeFile } = require('../../io')({ output: 'dist', @@ -30,7 +29,7 @@ describe('static build', () => { it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -46,8 +45,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -62,31 +61,18 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -104,8 +90,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -120,26 +106,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -172,41 +145,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -239,41 +193,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -389,46 +324,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('index.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - background-color: #ef4444; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('index.css')).toIncludeCss( + css` + .btn { + border-radius: 0.25rem; + z-index: 0; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/tailwindcss-cli/tests/cli.test.js b/integrations/tailwindcss-cli/tests/cli.test.js index 0c42ce0cc..cf15425bb 100644 --- a/integrations/tailwindcss-cli/tests/cli.test.js +++ b/integrations/tailwindcss-cli/tests/cli.test.js @@ -2,7 +2,6 @@ let path = require('path') let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') let resolveToolRoot = require('../../resolve-tool-root') -let { env } = require('../../../lib/lib/sharedState') let version = require('../../../package.json').version @@ -19,7 +18,6 @@ let { }) let EXECUTABLE = 'node ../../lib/cli.js' -let testStable = env.ENGINE === 'stable' ? test : test.skip function dedent(input) { let lines = input.split('\n') @@ -98,7 +96,8 @@ describe('Build command', () => { expect(withoutMinify.length).toBeGreaterThan(withMinify.length) }) - testStable('--no-autoprefixer', async () => { + // TODO: Handle --no-autoprefixer + test.skip('--no-autoprefixer', async () => { await writeInputFile('index.html', html`
`) await $(`${EXECUTABLE} --output ./dist/main.css`) @@ -184,7 +183,7 @@ describe('Build command', () => { ) }) - testStable('--postcss (postcss.config.js)', async () => { + test('--postcss (postcss.config.js)', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -196,7 +195,7 @@ describe('Build command', () => { function before(root, result) { // Inject a custom component with @apply rules to prove that we run // this _before_ the actual tailwind plugin. - let btn = postcss.parse('.btn { @apply bg-red-500 px-2 py-1 }') + let btn = postcss.parse('.btn { @apply flex px-2 py-1 }') root.append(btn.nodes) }, function tailwindcss() { @@ -217,45 +216,24 @@ describe('Build command', () => { await $(`${EXECUTABLE} --output ./dist/main.css --postcss`) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold-after { + font-weight: 700; + } - .btn-after { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } - - .btn-after { - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } + .btn-after { + display: flex; + padding-left: 0.5rem; + padding-right: 0.5rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; + } + ` + ) }) - testStable('--postcss (custom.postcss.config.js)', async () => { + test('--postcss (custom.postcss.config.js)', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -267,7 +245,7 @@ describe('Build command', () => { function before(root, result) { // Inject a custom component with @apply rules to prove that we run // this _before_ the actual tailwind plugin. - let btn = postcss.parse('.btn { @apply bg-red-500 px-2 py-1 }') + let btn = postcss.parse('.btn { @apply flex px-2 py-1 }') root.append(btn.nodes) }, function tailwindcss() { @@ -288,45 +266,24 @@ describe('Build command', () => { await $(`${EXECUTABLE} --output ./dist/main.css --postcss ./custom.postcss.config.js`) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold-after { + font-weight: 700; + } - .btn-after { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold-after { - font-weight: 700; - } - - .btn-after { - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - ` - ) - } + .btn-after { + display: flex; + padding-left: 0.5rem; + padding-right: 0.5rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; + } + ` + ) }) - testStable('--postcss supports process options', async () => { + test('--postcss supports process options', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -360,7 +317,7 @@ describe('Build command', () => { expect(contents).toContain(`/*# sourceMappingURL`) }) - testStable('--postcss supports process options with custom config', async () => { + test('--postcss supports process options with custom config', async () => { await writeInputFile('index.html', html`
`) let customConfig = javascript` @@ -481,10 +438,18 @@ describe('Build command', () => { return runningProcess.stop() }) - testStable('postcss-import is included when using a custom postcss configuration', async () => { + test('postcss-import is included when using a custom postcss configuration', async () => { cleanupFile('src/test.css') await writeInputFile('index.html', html`
`) + await writeInputFile( + 'imported.css', + css` + .foo { + color: white; + } + ` + ) await writeInputFile( 'test.css', css` @@ -501,7 +466,9 @@ describe('Build command', () => { expect(await readOutputFile('main.css')).toIncludeCss( css` - @import './imported.css'; + .foo { + color: #fff; + } ` ) }) @@ -509,28 +476,8 @@ describe('Build command', () => { test('--help', async () => { let { combined } = await $(`${EXECUTABLE} --help`) - if (env.ENGINE === 'oxide') { - expect(dedent(combined)).toEqual( - dedent(` - tailwindcss v${version} - - Usage: - tailwindcss build [options] - - Options: - -i, --input Input file - -o, --output Output file - -w, --watch Watch for changes and rebuild as needed - -p, --poll Use polling instead of filesystem events when watching - --content Content paths to use for removing unused classes - -m, --minify Minify the output - -c, --config Path to a custom config file - -h, --help Display usage information - `) - ) - } else if (env.ENGINE === 'stable') { - expect(dedent(combined)).toEqual( - dedent(` + expect(dedent(combined)).toEqual( + dedent(` tailwindcss v${version} Usage: @@ -548,8 +495,7 @@ describe('Build command', () => { --no-autoprefixer Disable autoprefixer -h, --help Display usage information `) - ) - } + ) }) }) @@ -562,7 +508,6 @@ describe('Init command', () => { { flags: ['--ts', '--full'], name: 'tailwind.config.ts' }, { flags: ['--esm', '--full'], name: 'tailwind.config.js' }, ])('works with all these flags: %j', async ({ flags, name }) => { - cleanupFile(name) await removeFile(name) let { combined } = await $(`${EXECUTABLE} init ${flags.join(' ')}`) @@ -611,7 +556,7 @@ describe('Init command', () => { expect((await readOutputFile('../full.config.js')).split('\n').length).toBeGreaterThan(50) }) - testStable('--postcss', async () => { + test('--postcss', async () => { expect(await fileExists('postcss.config.js')).toBe(true) await removeFile('postcss.config.js') expect(await fileExists('postcss.config.js')).toBe(false) @@ -631,24 +576,8 @@ describe('Init command', () => { test('--help', async () => { let { combined } = await $(`${EXECUTABLE} init --help`) - if (env.ENGINE === 'oxide') { - expect(dedent(combined)).toEqual( - dedent(` - tailwindcss v${version} - - Usage: - tailwindcss init [options] - - Options: - --esm Initialize configuration file as ESM - --ts Initialize configuration file as TypeScript - -f, --full Include the default values for all options in the generated configuration file - -h, --help Display usage information - `) - ) - } else if (env.ENGINE === 'stable') { - expect(dedent(combined)).toEqual( - dedent(` + expect(dedent(combined)).toEqual( + dedent(` tailwindcss v${version} Usage: @@ -661,12 +590,10 @@ describe('Init command', () => { -f, --full Include the default values for all options in the generated configuration file -h, --help Display usage information `) - ) - } + ) }) test('ESM config is created by default in an ESM project', async () => { - cleanupFile('tailwind.config.js') await removeFile('tailwind.config.js') let pkg = await readOutputFile('../package.json') @@ -696,7 +623,6 @@ describe('Init command', () => { }) test('CJS config is created by default in a non-ESM project', async () => { - cleanupFile('tailwind.config.js') await removeFile('tailwind.config.js') let pkg = await readOutputFile('../package.json') diff --git a/integrations/tailwindcss-cli/tests/integration.test.js b/integrations/tailwindcss-cli/tests/integration.test.js index de806dd27..c72728dd6 100644 --- a/integrations/tailwindcss-cli/tests/integration.test.js +++ b/integrations/tailwindcss-cli/tests/integration.test.js @@ -2,7 +2,6 @@ let fs = require('fs') let path = require('path') let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile, removeFile } = require('../../io')({ output: 'dist', @@ -56,7 +55,7 @@ describe('static build', () => { content: { files: ['./src/index.html'], }, - safelist: ['bg-red-500','bg-red-600'], + safelist: ['flex','block'], theme: { extend: { }, @@ -73,48 +72,26 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .block { + display: block; + } - .bg-red-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); - } + .flex { + display: flex; + } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - - .bg-red-600 { - background-color: #dc2626; - } - - .font-bold { - font-weight: 700; - } - ` - ) - } + .font-bold { + font-weight: 700; + } + ` + ) }) it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -130,8 +107,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0 }, }, }, @@ -146,31 +123,18 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -188,8 +152,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0 }, }, }, @@ -204,30 +168,17 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can read from a config file from an @config directive', async () => { - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -247,8 +198,8 @@ describe('static build', () => { }, theme: { extend: { - colors: { - yellow: '#ff0', + zIndex: { + primary: 0 } }, }, @@ -263,32 +214,19 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff0; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can read from a config file from an @config directive inside an @import from postcss-import', async () => { await fs.promises.mkdir('./src/config', { recursive: true }) - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'config/myconfig.css', css` @@ -314,8 +252,8 @@ describe('static build', () => { }, theme: { extend: { - colors: { - yellow: '#ff0', + zIndex: { + primary: 0 } }, }, @@ -330,26 +268,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff0; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('should work with raw content', async () => { @@ -358,7 +283,7 @@ describe('static build', () => { javascript` module.exports = { content: { - files: [{ raw: 'bg-red-500'}], + files: [{ raw: 'flex'}], }, theme: { extend: { @@ -376,26 +301,13 @@ describe('static build', () => { env: { NODE_ENV: 'production' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .flex { + display: flex; + } + ` + ) }) }) @@ -428,41 +340,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .flex { + display: flex; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -495,41 +388,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .flex { + display: flex; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -697,55 +571,31 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded flex px-2 py-1; } } ` ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .btn { + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + display: flex; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) test('listens for changes to the @config directive', async () => { - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -765,8 +615,8 @@ describe('watcher', () => { }, theme: { extend: { - colors: { - yellow: '#ff0', + zIndex: { + primary: 0 } }, }, @@ -786,8 +636,8 @@ describe('watcher', () => { }, theme: { extend: { - colors: { - yellow: '#ff7', + zIndex: { + primary: 10 } }, }, @@ -801,26 +651,13 @@ describe('watcher', () => { let runningProcess = $('node ../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w') await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff0; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) await writeInputFile( 'index.css', @@ -833,26 +670,13 @@ describe('watcher', () => { ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 119 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #ff7; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 10; + } + ` + ) await writeInputFile( 'tailwind.2.config.js', @@ -864,8 +688,8 @@ describe('watcher', () => { }, theme: { extend: { - colors: { - yellow: '#fff', + zIndex: { + primary: 20 } }, }, @@ -877,26 +701,13 @@ describe('watcher', () => { ) await runningProcess.onStderr(ready) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-yellow { - background-color: #fff; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 20; + } + ` + ) return runningProcess.stop() }) @@ -1002,435 +813,565 @@ describe('watcher', () => { return runningProcess.stop() }) - if (env.ENGINE === 'oxide') { - describe('auto content', () => { - let { readOutputFile, writeInputFile } = require('../../io')({ - output: 'fixtures/example-app/dist', - input: 'fixtures/example-app/src', - }) - let options = { - cwd: path.resolve(__dirname, '..', 'fixtures', 'example-app'), - } - - it('should detect classes in existing files', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - - await writeInputFile('index.html', html`
`) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - return runningProcess.stop() - }) - - it('should detect changes in existing files', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - - await writeInputFile('index.html', html`
`) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; - } - ` - ) - - // Make a change - - await writeInputFile('index.html', html`
`) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; - } - ` - ) - - return runningProcess.stop() - }) - - it('should detect changes in new files in existing folders with a known extension', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - - await writeInputFile('index.html', html`
`) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; - } - ` - ) - - // Make a change to a new file in an existing folder with a known extension. - - await writeInputFile('other.html', html`
`) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; - } - ` - ) - - return runningProcess.stop() - }) - - it('should not scan ignored files', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - await writeInputFile('../.gitignore', 'generated-folder/') - await writeInputFile('../generated-folder/bad.html', html`
`) - await writeInputFile('index.html', html`
`) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .italic { - font-style: italic; - } - ` - ) - - return runningProcess.stop() - }) - - it('should not scan for known binary files', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - await writeInputFile('example-1.png', html`
`) - await writeInputFile('example-2.mp4', html`
`) - await writeInputFile('index.html', html`
`) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .italic { - font-style: italic; - } - - .underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; - } - ` - ) - - return runningProcess.stop() - }) - - it('should not scan for explicitly ignored extensions (such as css/scss/less/...)', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - await writeInputFile('example.css', html`
`) - await writeInputFile('example.less', html`
`) - await writeInputFile('index.html', html`
`) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .italic { - font-style: italic; - } - - .underline { - -webkit-text-decoration-line: underline; - text-decoration-line: underline; - } - ` - ) - - return runningProcess.stop() - }) - - it('should not scan for explicitly ignored files (such as package-lock.json)', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - await writeInputFile('package-lock.json', html`
`) - await writeInputFile('yarn.lock', html`
`) - await writeInputFile('pnpm-lock.yaml', html`
`) - await writeInputFile('index.html', html`
`) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .italic { - font-style: italic; - } - ` - ) - - return runningProcess.stop() - }) - - it('should not include the tailwind.config.js file as a template file', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - // Example class that should not be included: flex italic - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - await writeInputFile('index.html', html`
`) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .font-bold { - font-weight: 700; - } - ` - ) - - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .flex { - display: flex; - } - ` - ) - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .italic { - font-style: italic; - } - ` - ) - - return runningProcess.stop() - }) - - it('should optimize the globs and ensure that nested ignored folders are not scanned', async () => { - await writeInputFile( - '../tailwind.config.js', - javascript` - module.exports = { - corePlugins: { - preflight: false, - }, - } - ` - ) - - await writeInputFile('../.gitignore', 'node_modules') - await writeInputFile('../node_modules/a.html', html`
`) - await writeInputFile('index.html', html`
`) - await writeInputFile('nested/index.html', html`
`) - await writeInputFile( - 'nested/node_modules/index.html', - html`
` - ) - - let runningProcess = $( - 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', - options - ) - await runningProcess.onStderr(ready) - - // Root node_modules - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .text-red-100 { - color: #fee2e2; - } - ` - ) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .text-red-200 { - color: #fecaca; - } - ` - ) - - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .text-red-300 { - color: #fca5a5; - } - ` - ) - - // Nested node_modules - expect(await readOutputFile('main.css')).not.toIncludeCss( - css` - .text-red-400 { - color: #f87171; - } - ` - ) - - return runningProcess.stop() - }) + describe('auto content', () => { + let { readOutputFile, writeInputFile } = require('../../io')({ + output: 'fixtures/example-app/dist', + input: 'fixtures/example-app/src', }) - } + let options = { + cwd: path.resolve(__dirname, '..', 'fixtures', 'example-app'), + } + + it('should detect classes in existing files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + + await writeInputFile('index.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + return runningProcess.stop() + }) + + it('should detect changes in existing files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + // Make a change + + await writeInputFile('index.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should detect changes in new files in existing folders with a known extension', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + // Make a change to a new file in an existing folder with a known extension. + + await writeInputFile('other.html', html`
`) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan ignored files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('../.gitignore', 'generated-folder/') + await writeInputFile('../generated-folder/bad.html', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for known binary files', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('example-1.png', html`
`) + await writeInputFile('example-2.mp4', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for explicitly ignored extensions (such as css/scss/less/...)', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('example.css', html`
`) + await writeInputFile('example.less', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + + .underline { + -webkit-text-decoration-line: underline; + text-decoration-line: underline; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not scan for explicitly ignored files (such as package-lock.json)', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('package-lock.json', html`
`) + await writeInputFile('yarn.lock', html`
`) + await writeInputFile('pnpm-lock.yaml', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should not include the tailwind.config.js file as a template file', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + // Example class that should not be included: flex italic + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .font-bold { + font-weight: 700; + } + ` + ) + + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .flex { + display: flex; + } + ` + ) + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .italic { + font-style: italic; + } + ` + ) + + return runningProcess.stop() + }) + + it('should optimize the globs and ensure that nested ignored folders are not scanned', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('../.gitignore', 'node_modules') + await writeInputFile('../node_modules/a.html', html`
`) + await writeInputFile('index.html', html`
`) + await writeInputFile('nested/index.html', html`
`) + await writeInputFile('nested/node_modules/index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + // Root node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-30 { + z-index: 30; + } + ` + ) + + // Nested node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-40 { + z-index: 40; + } + ` + ) + + return runningProcess.stop() + }) + + it("should use auto content when content is explicitly set to 'auto'", async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + content: 'auto', + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('../.gitignore', 'node_modules') + await writeInputFile('../node_modules/a.html', html`
`) + await writeInputFile('index.html', html`
`) + await writeInputFile('nested/index.html', html`
`) + await writeInputFile('nested/node_modules/index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + // Root node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-30 { + z-index: 30; + } + ` + ) + + // Nested node_modules + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-40 { + z-index: 40; + } + ` + ) + + return runningProcess.stop() + }) + + it('should be possible to merge "auto" and custom defined paths', async () => { + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + content: ['auto'], // Ignoring the library-example.html file for now + corePlugins: { + preflight: false, + }, + } + ` + ) + + await writeInputFile('../.gitignore', 'node_modules') + await writeInputFile('../node_modules/library-example.html', html`
`) + await writeInputFile('index.html', html`
`) + + let runningProcess = $( + 'node ../../../../lib/cli.js -i ./src/index.css -o ./dist/main.css -w', + options + ) + await runningProcess.onStderr(ready) + + // example.html should be ignored right now + expect(await readOutputFile('main.css')).not.toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + await writeInputFile( + '../tailwind.config.js', + javascript` + module.exports = { + content: ['auto', 'node_modules/library-example.html'], // Explicitly adding the library-example.html file + corePlugins: { + preflight: false, + }, + } + ` + ) + await runningProcess.onStderr(ready) + + // z-10 from `example.html` should be available now + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-10 { + z-index: 10; + } + ` + ) + + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-20 { + z-index: 20; + } + ` + ) + + return runningProcess.stop() + }) + }) }) diff --git a/integrations/vite/tests/integration.test.js b/integrations/vite/tests/integration.test.js index b1a8163b2..cb106ac59 100644 --- a/integrations/vite/tests/integration.test.js +++ b/integrations/vite/tests/integration.test.js @@ -2,7 +2,6 @@ require('isomorphic-fetch') let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { readOutputFile, appendToInputFile, writeInputFile, removeFile } = require('../../io')({ output: 'dist', @@ -48,7 +47,7 @@ describe('static build', () => { 'index.html', html` -
+
` ) await removeFile('tailwind.config.js') @@ -59,8 +58,8 @@ describe('static build', () => { content: ['index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -75,26 +74,13 @@ describe('static build', () => { env: { NODE_ENV: 'production', NO_COLOR: '1' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { @@ -102,7 +88,7 @@ describe('static build', () => { 'index.html', html` -
+
` ) await removeFile('tailwind.config.js') @@ -115,8 +101,8 @@ describe('static build', () => { content: ['index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -131,26 +117,13 @@ describe('static build', () => { env: { NODE_ENV: 'production', NO_COLOR: '1' }, }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile(/index.\w+\.css$/)).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -191,41 +164,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) await runningProcess.onStdout((message) => message.includes('page reload')) - if (env.ENGINE === 'stable') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await fetchCSS()).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -262,41 +216,22 @@ describe('watcher', () => { ` ) - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) await runningProcess.onStdout((message) => message.includes('page reload')) - if (env.ENGINE === 'stable') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await fetchCSS()).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await fetchCSS()).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -428,49 +363,28 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) await runningProcess.onStdout((message) => message.includes('hmr update /index.css')) - if (env.ENGINE === 'stable') { - expect(await fetchCSS()).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await fetchCSS()).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - background-color: #ef4444; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await fetchCSS()).toIncludeCss( + css` + .btn { + border-radius: 0.25rem; + z-index: 0; + padding-left: 0.5rem; + padding-right: 0.5rem; + padding-top: 0.25rem; + padding-bottom: 0.25rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/webpack-4/tests/integration.test.js b/integrations/webpack-4/tests/integration.test.js index e2e24cf45..ae7011edd 100644 --- a/integrations/webpack-4/tests/integration.test.js +++ b/integrations/webpack-4/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { appendToInputFile, @@ -28,7 +27,7 @@ describe('static build', () => { it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -44,8 +43,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -58,31 +57,18 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -100,8 +86,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -114,26 +100,13 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -169,41 +142,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -239,41 +193,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('glob/index.html', html`
`) + await appendToInputFile('glob/index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -394,46 +329,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/integrations/webpack-5/tests/integration.test.js b/integrations/webpack-5/tests/integration.test.js index 83b42f5f8..c1f0a0629 100644 --- a/integrations/webpack-5/tests/integration.test.js +++ b/integrations/webpack-5/tests/integration.test.js @@ -1,6 +1,5 @@ let $ = require('../../execute') let { css, html, javascript } = require('../../syntax') -let { env } = require('../../../lib/lib/sharedState') let { appendToInputFile, @@ -28,7 +27,7 @@ describe('static build', () => { it('can use a tailwind.config.js configuration file with ESM syntax', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -44,8 +43,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -58,31 +57,18 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) it('can use a tailwind.config.ts configuration file', async () => { await removeFile('tailwind.config.js') - await writeInputFile('index.html', html`
`) + await writeInputFile('index.html', html`
`) await writeInputFile( 'index.css', css` @@ -100,8 +86,8 @@ describe('static build', () => { content: ['./src/index.html'], theme: { extend: { - colors: { - primary: 'black', + zIndex: { + primary: 0, }, }, }, @@ -114,26 +100,13 @@ describe('static build', () => { await $('webpack --mode=production') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-primary { - background-color: black; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-primary { + z-index: 0; + } + ` + ) }) }) @@ -169,41 +142,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -239,41 +193,22 @@ describe('watcher', () => { ) await waitForOutputFileChange('main.css', async () => { - await appendToInputFile('index.html', html`
`) + await appendToInputFile('index.html', html`
`) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - .font-bold { - font-weight: 700; - } - .font-normal { - font-weight: 400; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } + .font-bold { + font-weight: 700; + } + .font-normal { + font-weight: 400; + } + ` + ) return runningProcess.stop() }) @@ -394,46 +329,25 @@ describe('watcher', () => { @layer components { .btn { - @apply rounded bg-red-500 px-2 py-1; + @apply rounded z-0 px-2 py-1; } } ` ) }) - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - border-radius: 0.25rem; - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .btn { - background-color: #ef4444; - border-radius: 0.25rem; - padding: 0.25rem 0.5rem; - } - .font-bold { - font-weight: 700; - } - ` - ) - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .btn { + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) @@ -447,7 +361,7 @@ describe('watcher', () => { content: { files: ['./src/index.html'], }, - safelist: ['bg-red-500','bg-red-600'], + safelist: ['z-0', 'z-10'], theme: { extend: { }, @@ -464,43 +378,21 @@ describe('watcher', () => { await waitForOutputFileCreation('main.css') - if (env.ENGINE === 'stable') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } + expect(await readOutputFile('main.css')).toIncludeCss( + css` + .z-0 { + z-index: 0; + } - .bg-red-600 { - --tw-bg-opacity: 1; - background-color: rgb(220 38 38 / var(--tw-bg-opacity)); - } + .z-10 { + z-index: 10; + } - .font-bold { - font-weight: 700; - } - ` - ) - } - - if (env.ENGINE === 'oxide') { - expect(await readOutputFile('main.css')).toIncludeCss( - css` - .bg-red-500 { - background-color: #ef4444; - } - - .bg-red-600 { - background-color: #dc2626; - } - - .font-bold { - font-weight: 700; - } - ` - ) - } + .font-bold { + font-weight: 700; + } + ` + ) return runningProcess.stop() }) diff --git a/package-lock.json b/package-lock.json index 4467139ea..ad784d3cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,8 +51,6 @@ "@swc/register": "^0.1.10", "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", - "cssnano": "^6.0.1", - "esbuild": "^0.17.18", "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", @@ -6585,6 +6583,8 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -6601,6 +6601,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -6615,6 +6617,8 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "domelementtype": "^2.3.0" }, @@ -6630,6 +6634,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -6644,6 +6650,8 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.12" }, @@ -6656,6 +6664,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -6691,6 +6701,8 @@ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "cssnano-preset-default": "^6.0.1", "lilconfig": "^2.1.0" @@ -6711,6 +6723,8 @@ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^4.0.0", @@ -6754,6 +6768,8 @@ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" @@ -6770,6 +6786,8 @@ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -6782,6 +6800,8 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "css-tree": "~2.2.0" }, @@ -6795,6 +6815,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -6808,7 +6830,9 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/cyclist": { "version": "1.0.1", @@ -10828,7 +10852,9 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/memory-fs": { "version": "0.4.1", @@ -12013,6 +12039,8 @@ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -12031,6 +12059,8 @@ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -12047,6 +12077,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -12059,6 +12091,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -12071,6 +12105,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -12083,6 +12119,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -12222,6 +12260,8 @@ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0", "stylehacks": "^6.0.0" @@ -12238,6 +12278,8 @@ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -12256,6 +12298,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12271,6 +12315,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "colord": "^2.9.1", "cssnano-utils": "^4.0.0", @@ -12288,6 +12334,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "browserslist": "^4.21.4", "cssnano-utils": "^4.0.0", @@ -12305,6 +12353,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-selector-parser": "^6.0.5" }, @@ -12416,6 +12466,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "^14 || ^16 || >=18.0" }, @@ -12428,6 +12480,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12443,6 +12497,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12458,6 +12514,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12473,6 +12531,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12488,6 +12548,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12503,6 +12565,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -12519,6 +12583,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12534,6 +12600,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12549,6 +12617,8 @@ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "cssnano-utils": "^4.0.0", "postcss-value-parser": "^4.2.0" @@ -12565,6 +12635,8 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" @@ -12581,6 +12653,8 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0" }, @@ -12628,6 +12702,8 @@ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-value-parser": "^4.2.0", "svgo": "^3.0.2" @@ -12644,6 +12720,8 @@ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "postcss-selector-parser": "^6.0.5" }, @@ -14785,6 +14863,8 @@ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "browserslist": "^4.21.4", "postcss-selector-parser": "^6.0.4" @@ -14864,6 +14944,8 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -21154,6 +21236,8 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "requires": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -21167,6 +21251,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -21178,6 +21264,8 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0" } @@ -21187,6 +21275,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", "dev": true, + "optional": true, + "peer": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -21197,7 +21287,9 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -21206,6 +21298,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -21225,6 +21319,8 @@ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", "dev": true, + "optional": true, + "peer": true, "requires": { "cssnano-preset-default": "^6.0.1", "lilconfig": "^2.1.0" @@ -21235,6 +21331,8 @@ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^4.0.0", @@ -21272,6 +21370,8 @@ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" @@ -21284,6 +21384,8 @@ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "csso": { @@ -21291,6 +21393,8 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "css-tree": "~2.2.0" }, @@ -21300,6 +21404,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -21309,7 +21415,9 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -24259,7 +24367,9 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "memory-fs": { "version": "0.4.1", @@ -25114,6 +25224,8 @@ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -25126,6 +25238,8 @@ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -25136,6 +25250,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-discard-duplicates": { @@ -25143,6 +25259,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-discard-empty": { @@ -25150,6 +25268,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-discard-overridden": { @@ -25157,6 +25277,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-import": { @@ -25233,6 +25355,8 @@ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0", "stylehacks": "^6.0.0" @@ -25243,6 +25367,8 @@ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -25255,6 +25381,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25264,6 +25392,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", "dev": true, + "optional": true, + "peer": true, "requires": { "colord": "^2.9.1", "cssnano-utils": "^4.0.0", @@ -25275,6 +25405,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "cssnano-utils": "^4.0.0", @@ -25286,6 +25418,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-selector-parser": "^6.0.5" } @@ -25355,6 +25489,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-normalize-display-values": { @@ -25362,6 +25498,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25371,6 +25509,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25380,6 +25520,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25389,6 +25531,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25398,6 +25542,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25407,6 +25553,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -25417,6 +25565,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25426,6 +25576,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25435,6 +25587,8 @@ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", "dev": true, + "optional": true, + "peer": true, "requires": { "cssnano-utils": "^4.0.0", "postcss-value-parser": "^4.2.0" @@ -25445,6 +25599,8 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" @@ -25455,6 +25611,8 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -25483,6 +25641,8 @@ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0", "svgo": "^3.0.2" @@ -25493,6 +25653,8 @@ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-selector-parser": "^6.0.5" } @@ -27038,6 +27200,8 @@ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "postcss-selector-parser": "^6.0.4" @@ -27089,6 +27253,8 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", @@ -27121,10 +27287,8 @@ "browserslist": "^4.21.5", "chokidar": "^3.5.3", "concurrently": "^8.0.1", - "cssnano": "^6.0.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "esbuild": "^0.17.18", "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", @@ -31818,6 +31982,8 @@ "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", "dev": true, + "optional": true, + "peer": true, "requires": { "boolbase": "^1.0.0", "css-what": "^6.1.0", @@ -31831,6 +31997,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", @@ -31842,6 +32010,8 @@ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", "dev": true, + "optional": true, + "peer": true, "requires": { "domelementtype": "^2.3.0" } @@ -31851,6 +32021,8 @@ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", "dev": true, + "optional": true, + "peer": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", @@ -31861,7 +32033,9 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -31870,6 +32044,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -31889,6 +32065,8 @@ "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", "dev": true, + "optional": true, + "peer": true, "requires": { "cssnano-preset-default": "^6.0.1", "lilconfig": "^2.1.0" @@ -31899,6 +32077,8 @@ "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "css-declaration-sorter": "^6.3.1", "cssnano-utils": "^4.0.0", @@ -31936,6 +32116,8 @@ "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-selector-parser": "^6.0.11", "postcss-value-parser": "^4.2.0" @@ -31948,6 +32130,8 @@ "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "csso": { @@ -31955,6 +32139,8 @@ "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "css-tree": "~2.2.0" }, @@ -31964,6 +32150,8 @@ "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", "dev": true, + "optional": true, + "peer": true, "requires": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" @@ -31973,7 +32161,9 @@ "version": "2.0.28", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true + "dev": true, + "optional": true, + "peer": true } } }, @@ -34923,7 +35113,9 @@ "version": "2.0.30", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "memory-fs": { "version": "0.4.1", @@ -35778,6 +35970,8 @@ "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -35790,6 +35984,8 @@ "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -35800,6 +35996,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-discard-duplicates": { @@ -35807,6 +36005,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-discard-empty": { @@ -35814,6 +36014,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-discard-overridden": { @@ -35821,6 +36023,8 @@ "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-import": { @@ -35897,6 +36101,8 @@ "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0", "stylehacks": "^6.0.0" @@ -35907,6 +36113,8 @@ "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0", @@ -35919,6 +36127,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -35928,6 +36138,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", "dev": true, + "optional": true, + "peer": true, "requires": { "colord": "^2.9.1", "cssnano-utils": "^4.0.0", @@ -35939,6 +36151,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "cssnano-utils": "^4.0.0", @@ -35950,6 +36164,8 @@ "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-selector-parser": "^6.0.5" } @@ -36019,6 +36235,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", "dev": true, + "optional": true, + "peer": true, "requires": {} }, "postcss-normalize-display-values": { @@ -36026,6 +36244,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36035,6 +36255,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36044,6 +36266,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36053,6 +36277,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36062,6 +36288,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36071,6 +36299,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "postcss-value-parser": "^4.2.0" @@ -36081,6 +36311,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36090,6 +36322,8 @@ "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36099,6 +36333,8 @@ "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", "dev": true, + "optional": true, + "peer": true, "requires": { "cssnano-utils": "^4.0.0", "postcss-value-parser": "^4.2.0" @@ -36109,6 +36345,8 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "caniuse-api": "^3.0.0" @@ -36119,6 +36357,8 @@ "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0" } @@ -36147,6 +36387,8 @@ "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-value-parser": "^4.2.0", "svgo": "^3.0.2" @@ -36157,6 +36399,8 @@ "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", "dev": true, + "optional": true, + "peer": true, "requires": { "postcss-selector-parser": "^6.0.5" } @@ -37702,6 +37946,8 @@ "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", "dev": true, + "optional": true, + "peer": true, "requires": { "browserslist": "^4.21.4", "postcss-selector-parser": "^6.0.4" @@ -37753,6 +37999,8 @@ "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", "dev": true, + "optional": true, + "peer": true, "requires": { "@trysound/sax": "0.2.0", "commander": "^7.2.0", diff --git a/package-lock.stable.json b/package-lock.stable.json deleted file mode 100644 index 4d422e6a2..000000000 --- a/package-lock.stable.json +++ /dev/null @@ -1,13997 +0,0 @@ -{ - "name": "tailwindcss", - "version": "3.3.2", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "tailwindcss", - "version": "3.3.2", - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "devDependencies": { - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", - "@swc/jest": "^0.2.26", - "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", - "browserslist": "^4.21.5", - "concurrently": "^8.0.1", - "cssnano": "^6.0.0", - "esbuild": "^0.17.18", - "eslint": "^8.39.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", - "jest": "^29.5.0", - "jest-diff": "^29.5.0", - "lightningcss": "1.18.0", - "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "source-map-js": "^1.0.2", - "turbo": "^1.9.3" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "integrations/content-resolution": { - "name": "@tailwindcss/integrations-content-resolution", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "postcss": "^8.4.21", - "postcss-cli": "^9.1.0" - } - }, - "integrations/parcel": { - "name": "@tailwindcss/integrations-parcel", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "parcel": "^2.5.0" - } - }, - "integrations/postcss-cli": { - "name": "@tailwindcss/integrations-postcss-cli", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "postcss": "^8.4.21", - "postcss-cli": "^9.1.0" - } - }, - "integrations/rollup": { - "name": "@tailwindcss/integrations-rollup", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "rollup": "^2.74.1", - "rollup-plugin-postcss": "^4.0.2" - } - }, - "integrations/rollup-sass": { - "name": "@tailwindcss/integrations-rollup-sass", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "rollup": "^2.74.1", - "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.51.0" - } - }, - "integrations/tailwindcss-cli": { - "name": "@tailwindcss/integrations-tailwindcss-cli", - "version": "0.0.0", - "extraneous": true, - "dependencies": { - "tailwindcss": "file:../../" - } - }, - "integrations/vite": { - "name": "@tailwindcss/integrations-vite", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "isomorphic-fetch": "^3.0.0", - "vite": "^2.9.9" - } - }, - "integrations/webpack-4": { - "name": "@tailwindcss/integrations-webpack-4", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "css-loader": "^5.2.7", - "mini-css-extract-plugin": "^1.6.2", - "postcss-loader": "^4.3.0", - "webpack": "^4.46.0", - "webpack-cli": "^4.9.2" - } - }, - "integrations/webpack-5": { - "name": "@tailwindcss/integrations-webpack-5", - "version": "0.0.0", - "extraneous": true, - "devDependencies": { - "css-loader": "^6.7.1", - "mini-css-extract-plugin": "^2.7.2", - "postcss-loader": "^6.2.1", - "webpack": "^5.75.0", - "webpack-cli": "^5.0.1" - } - }, - "node_modules/@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.21.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.20.2" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", - "dev": true, - "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "node_modules/@esbuild/android-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz", - "integrity": "sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz", - "integrity": "sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.18.tgz", - "integrity": "sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz", - "integrity": "sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz", - "integrity": "sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz", - "integrity": "sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz", - "integrity": "sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz", - "integrity": "sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz", - "integrity": "sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz", - "integrity": "sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz", - "integrity": "sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz", - "integrity": "sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz", - "integrity": "sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz", - "integrity": "sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz", - "integrity": "sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz", - "integrity": "sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz", - "integrity": "sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz", - "integrity": "sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz", - "integrity": "sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz", - "integrity": "sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz", - "integrity": "sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz", - "integrity": "sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.1", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/console/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/core/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/core/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/create-cache-key-function": { - "version": "27.4.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^27.4.2" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "dependencies": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/environment/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "dependencies": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/fake-timers/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/globals/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "dependencies": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/@jest/reporters/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/reporters/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.25.16" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/test-result/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/transform/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@jest/types": { - "version": "27.5.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - } - }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - }, - "node_modules/@mole-inc/bin-wrapper": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", - "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", - "dev": true, - "dependencies": { - "bin-check": "^4.1.0", - "bin-version-check": "^5.0.0", - "content-disposition": "^0.5.4", - "ext-name": "^5.0.0", - "file-type": "^17.1.6", - "filenamify": "^5.0.2", - "got": "^11.8.5", - "os-filter-obj": "^2.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" - } - }, - "node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^2.0.0" - } - }, - "node_modules/@swc/cli": { - "version": "0.1.62", - "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.62.tgz", - "integrity": "sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==", - "dev": true, - "dependencies": { - "@mole-inc/bin-wrapper": "^8.0.1", - "commander": "^7.1.0", - "fast-glob": "^3.2.5", - "semver": "^7.3.8", - "slash": "3.0.0", - "source-map": "^0.7.3" - }, - "bin": { - "spack": "bin/spack.js", - "swc": "bin/swc.js", - "swcx": "bin/swcx.js" - }, - "engines": { - "node": ">= 12.13" - }, - "peerDependencies": { - "@swc/core": "^1.2.66", - "chokidar": "^3.5.1" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@swc/cli/node_modules/source-map": { - "version": "0.7.3", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", - "dev": true, - "hasInstallScript": true, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/swc" - }, - "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" - }, - "peerDependencies": { - "@swc/helpers": "^0.5.0" - }, - "peerDependenciesMeta": { - "@swc/helpers": { - "optional": true - } - } - }, - "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=10" - } - }, - "node_modules/@swc/jest": { - "version": "0.2.26", - "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.26.tgz", - "integrity": "sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==", - "dev": true, - "dependencies": { - "@jest/create-cache-key-function": "^27.4.2", - "jsonc-parser": "^3.2.0" - }, - "engines": { - "npm": ">= 7.0.0" - }, - "peerDependencies": { - "@swc/core": "*" - } - }, - "node_modules/@swc/register": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@swc/register/-/register-0.1.10.tgz", - "integrity": "sha512-6STwH/q4dc3pitXLVkV7sP0Hiy+zBsU2wOF1aXpXR95pnH3RYHKIsDC+gvesfyB7jxNT9OOZgcqOp9RPxVTx9A==", - "dev": true, - "dependencies": { - "lodash.clonedeep": "^4.5.0", - "pirates": "^4.0.1", - "source-map-support": "^0.5.13" - }, - "bin": { - "swc-node": "bin/swc-node" - }, - "peerDependencies": { - "@swc/core": "^1.0.46" - } - }, - "node_modules/@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "dependencies": { - "defer-to-connect": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "dev": true - }, - "node_modules/@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.3.0" - } - }, - "node_modules/@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "dependencies": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.3", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/node": { - "version": "16.10.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "node_modules/@types/yargs": { - "version": "16.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "dev": true, - "license": "MIT" - }, - "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "node_modules/anymatch": { - "version": "3.1.2", - "license": "ISC", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/arg": { - "version": "5.0.2", - "license": "MIT" - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "dependencies": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.8.0" - } - }, - "node_modules/babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "dependencies": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "dependencies": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "dependencies": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "license": "MIT" - }, - "node_modules/bin-check": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", - "dev": true, - "dependencies": { - "execa": "^0.7.0", - "executable": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/bin-version": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", - "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "find-versions": "^5.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version-check": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.0.0.tgz", - "integrity": "sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==", - "dev": true, - "dependencies": { - "bin-version": "^6.0.0", - "semver": "^7.3.5", - "semver-truncate": "^2.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/bin-version/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bin-version/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "dependencies": { - "node-int64": "^0.4.0" - } - }, - "node_modules/buffer-from": { - "version": "1.1.1", - "dev": true, - "license": "MIT" - }, - "node_modules/cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true, - "engines": { - "node": ">=10.6.0" - } - }, - "node_modules/cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "dependencies": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ] - }, - "node_modules/chalk": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/chokidar": { - "version": "3.5.3", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chokidar/node_modules/braces": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/fill-range": { - "version": "7.0.1", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/chokidar/node_modules/is-number": { - "version": "7.0.0", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/chokidar/node_modules/to-regex-range": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "engines": { - "node": ">=8" - } - }, - "node_modules/cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "dependencies": { - "mimic-response": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true, - "engines": { - "iojs": ">= 1.0.0", - "node": ">= 0.12.0" - } - }, - "node_modules/collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true - }, - "node_modules/commander": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "license": "MIT" - }, - "node_modules/concurrently": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.0.1.tgz", - "integrity": "sha512-Sh8bGQMEL0TAmAm2meAXMjcASHZa7V0xXQVDBLknCPa9TPtkY9yYs+0cnGGgfdkW0SV1Mlg+hVGfXcoI8d3MJA==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "date-fns": "^2.29.3", - "lodash": "^4.17.21", - "rxjs": "^7.8.0", - "shell-quote": "^1.8.0", - "spawn-command": "0.0.2-1", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.1" - }, - "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" - }, - "engines": { - "node": "^14.13.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" - } - }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "8.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "dependencies": { - "safe-buffer": "5.2.1" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.0.9" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", - "dev": true, - "dependencies": { - "cssnano-preset-default": "^6.0.0", - "lilconfig": "^2.1.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", - "dev": true, - "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "dependencies": { - "css-tree": "~2.2.0" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "dependencies": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", - "npm": ">=7.0.0" - } - }, - "node_modules/csso/node_modules/mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true - }, - "node_modules/date-fns": { - "version": "2.29.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.11" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/date-fns" - } - }, - "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decompress-response/node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "node_modules/deep-is": { - "version": "0.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/didyoumean": { - "version": "1.2.2", - "license": "Apache-2.0" - }, - "node_modules/diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dlv": { - "version": "1.1.3", - "license": "MIT" - }, - "node_modules/doctrine": { - "version": "3.0.0", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", - "dev": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.371", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz", - "integrity": "sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==", - "dev": true - }, - "node_modules/emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sindresorhus/emittery?sponsor=1" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/esbuild": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz", - "integrity": "sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/android-arm": "0.17.18", - "@esbuild/android-arm64": "0.17.18", - "@esbuild/android-x64": "0.17.18", - "@esbuild/darwin-arm64": "0.17.18", - "@esbuild/darwin-x64": "0.17.18", - "@esbuild/freebsd-arm64": "0.17.18", - "@esbuild/freebsd-x64": "0.17.18", - "@esbuild/linux-arm": "0.17.18", - "@esbuild/linux-arm64": "0.17.18", - "@esbuild/linux-ia32": "0.17.18", - "@esbuild/linux-loong64": "0.17.18", - "@esbuild/linux-mips64el": "0.17.18", - "@esbuild/linux-ppc64": "0.17.18", - "@esbuild/linux-riscv64": "0.17.18", - "@esbuild/linux-s390x": "0.17.18", - "@esbuild/linux-x64": "0.17.18", - "@esbuild/netbsd-x64": "0.17.18", - "@esbuild/openbsd-x64": "0.17.18", - "@esbuild/sunos-x64": "0.17.18", - "@esbuild/win32-arm64": "0.17.18", - "@esbuild/win32-ia32": "0.17.18", - "@esbuild/win32-x64": "0.17.18" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", - "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "4.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "eslint": ">=7.28.0", - "prettier": ">=2.0.0" - }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } - } - }, - "node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", - "dev": true, - "dependencies": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", - "dev": true, - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/execa/node_modules/lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "dependencies": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/execa/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/execa/node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - }, - "node_modules/executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "dependencies": { - "pify": "^2.2.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "dependencies": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "dev": true, - "dependencies": { - "mime-db": "^1.28.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "dev": true, - "dependencies": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/fast-glob": { - "version": "3.2.12", - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "dev": true, - "license": "MIT" - }, - "node_modules/fastq": { - "version": "1.11.0", - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "dependencies": { - "bser": "2.1.1" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/file-type": { - "version": "17.1.6", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", - "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", - "dev": true, - "dependencies": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0-alpha.9", - "token-types": "^5.0.0-alpha.2" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" - } - }, - "node_modules/filename-reserved-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", - "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/filenamify": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", - "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", - "dev": true, - "dependencies": { - "filename-reserved-regex": "^3.0.0", - "strip-outer": "^2.0.0", - "trim-repeated": "^2.0.0" - }, - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", - "dev": true, - "dependencies": { - "semver-regex": "^4.0.5" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.0.4", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flatted": { - "version": "3.1.1", - "dev": true, - "license": "ISC" - }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", - "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fraction.js": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.2", - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/glob": { - "version": "7.1.6", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - }, - "engines": { - "node": ">=10.19.0" - }, - "funding": { - "url": "https://github.com/sindresorhus/got?sponsor=1" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "dev": true, - "license": "MIT" - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "node_modules/http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "node_modules/http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "dependencies": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - }, - "engines": { - "node": ">=10.19.0" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "license": "ISC" - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", - "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", - "dev": true, - "dependencies": { - "cliui": "^7.0.4" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/jackspeak/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", - "import-local": "^3.0.2", - "jest-cli": "^29.5.0" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "dependencies": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-changed-files/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/jest-changed-files/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-changed-files/node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-circus/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "dependencies": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/jest-cli/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-cli/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "@types/node": "*", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/jest-config/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-config/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "dependencies": { - "detect-newline": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-each/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-environment-node/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "optionalDependencies": { - "fsevents": "^2.3.2" - } - }, - "node_modules/jest-haste-map/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-haste-map/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "dependencies": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-mock/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "engines": { - "node": ">=6" - }, - "peerDependencies": { - "jest-resolve": "*" - }, - "peerDependenciesMeta": { - "jest-resolve": { - "optional": true - } - } - }, - "node_modules/jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "dependencies": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "dependencies": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "dependencies": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runner/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-runner/node_modules/source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "dependencies": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-runtime/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "dependencies": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-snapshot/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "dependencies": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-validate/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "dependencies": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-watcher/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "dependencies": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/jest/node_modules/@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest/node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/js-sdsl": { - "version": "4.1.4", - "dev": true, - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/keyv": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", - "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/levn/node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/levn/node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", - "dev": true, - "dependencies": { - "detect-libc": "^1.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "license": "MIT" - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true - }, - "node_modules/lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "dependencies": { - "tmpl": "1.0.5" - } - }, - "node_modules/mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "license": "MIT", - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/braces": { - "version": "3.0.2", - "license": "MIT", - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "7.0.1", - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/is-number": { - "version": "7.0.0", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/micromatch/node_modules/to-regex-range": { - "version": "5.0.1", - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "dev": true, - "license": "MIT" - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-range": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-hash": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/once": { - "version": "1.4.0", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/prelude-ls": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/optionator/node_modules/type-check": { - "version": "0.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/os-filter-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", - "dev": true, - "dependencies": { - "arch": "^2.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "license": "MIT" - }, - "node_modules/path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", - "dev": true, - "dependencies": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", - "dev": true, - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/peek-readable": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", - "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", - "dev": true, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/picocolors": { - "version": "1.0.0", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pirates": { - "version": "4.0.4", - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - }, - "peerDependencies": { - "postcss": "^8.2.2" - } - }, - "node_modules/postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dependencies": { - "camelcase-css": "^2.0.1" - }, - "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" - } - }, - "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", - "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, - "engines": { - "node": ">= 14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } - } - }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "dependencies": { - "postcss-selector-parser": "^6.0.11" - }, - "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "dependencies": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - }, - "engines": { - "node": "^14 || ^16 || >= 18" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "license": "MIT" - }, - "node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "dependencies": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", - "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ] - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "5.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/read-cache": { - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dev": true, - "dependencies": { - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "dependencies": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "dependencies": { - "lowercase-keys": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", - "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", - "dev": true, - "dependencies": { - "glob": "^10.0.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", - "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dev": true, - "dependencies": { - "tslib": "^2.1.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/semver-truncate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-2.0.0.tgz", - "integrity": "sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/semver-truncate/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "dev": true, - "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", - "dev": true, - "dependencies": { - "sort-keys": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-js": { - "version": "1.0.2", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/spawn-command": { - "version": "0.0.2-1", - "dev": true, - "license": "MIT" - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "dependencies": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-outer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", - "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strtok3": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", - "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", - "dev": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", - "dev": true, - "dependencies": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - }, - "bin": { - "svgo": "bin/svgo" - }, - "engines": { - "node": ">=14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/svgo" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/token-types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", - "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", - "dev": true, - "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/trim-repeated": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", - "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^5.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/trim-repeated/node_modules/escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "node_modules/tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true - }, - "node_modules/turbo": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.9.3.tgz", - "integrity": "sha512-ID7mxmaLUPKG/hVkp+h0VuucB1U99RPCJD9cEuSEOdIPoSIuomcIClEJtKamUsdPLhLCud+BvapBNnhgh58Nzw==", - "dev": true, - "hasInstallScript": true, - "bin": { - "turbo": "bin/turbo" - }, - "optionalDependencies": { - "turbo-darwin-64": "1.9.3", - "turbo-darwin-arm64": "1.9.3", - "turbo-linux-64": "1.9.3", - "turbo-linux-arm64": "1.9.3", - "turbo-windows-64": "1.9.3", - "turbo-windows-arm64": "1.9.3" - } - }, - "node_modules/turbo-darwin-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.9.3.tgz", - "integrity": "sha512-0dFc2cWXl82kRE4Z+QqPHhbEFEpUZho1msHXHWbz5+PqLxn8FY0lEVOHkq5tgKNNEd5KnGyj33gC/bHhpZOk5g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/turbo-darwin-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.9.3.tgz", - "integrity": "sha512-1cYbjqLBA2zYE1nbf/qVnEkrHa4PkJJbLo7hnuMuGM0bPzh4+AnTNe98gELhqI1mkTWBu/XAEeF5u6dgz0jLNA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/turbo-linux-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.9.3.tgz", - "integrity": "sha512-UuBPFefawEwpuxh5pM9Jqq3q4C8M0vYxVYlB3qea/nHQ80pxYq7ZcaLGEpb10SGnr3oMUUs1zZvkXWDNKCJb8Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/turbo-linux-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.9.3.tgz", - "integrity": "sha512-vUrNGa3hyDtRh9W0MkO+l1dzP8Co2gKnOVmlJQW0hdpOlWlIh22nHNGGlICg+xFa2f9j4PbQlWTsc22c019s8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/turbo-windows-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.9.3.tgz", - "integrity": "sha512-0BZ7YaHs6r+K4ksqWus1GKK3W45DuDqlmfjm/yuUbTEVc8szmMCs12vugU2Zi5GdrdJSYfoKfEJ/PeegSLIQGQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/turbo-windows-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.9.3.tgz", - "integrity": "sha512-QJUYLSsxdXOsR1TquiOmLdAgtYcQ/RuSRpScGvnZb1hY0oLc7JWU0llkYB81wVtWs469y8H9O0cxbKwCZGR4RQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.0.10", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "license": "MIT", - "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist-lint": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "license": "MIT" - }, - "node_modules/v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "engines": { - "node": ">=10.12.0" - } - }, - "node_modules/v8-to-istanbul/node_modules/convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "node_modules/walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "dependencies": { - "makeerror": "1.0.12" - } - }, - "node_modules/which": { - "version": "2.0.2", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "license": "ISC" - }, - "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "oxide": { - "name": "tailwindcss-oxide", - "version": "0.1.0", - "extraneous": true, - "license": "MIT", - "workspaces": [ - "node" - ] - }, - "oxide-node-api-shim": { - "name": "@tailwindcss/oxide-shim", - "extraneous": true, - "license": "MIT" - }, - "oxide/crates/node": { - "name": "@tailwindcss/oxide", - "version": "0.0.0", - "extraneous": true, - "license": "MIT", - "devDependencies": { - "@napi-rs/cli": "^2.14.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-darwin-arm64": "0.0.0", - "@tailwindcss/oxide-darwin-x64": "0.0.0", - "@tailwindcss/oxide-freebsd-x64": "0.0.0", - "@tailwindcss/oxide-linux-arm-gnueabihf": "0.0.0", - "@tailwindcss/oxide-linux-arm64-gnu": "0.0.0", - "@tailwindcss/oxide-linux-arm64-musl": "0.0.0", - "@tailwindcss/oxide-linux-x64-gnu": "0.0.0", - "@tailwindcss/oxide-linux-x64-musl": "0.0.0", - "@tailwindcss/oxide-win32-x64-msvc": "0.0.0" - } - } - }, - "dependencies": { - "@alloc/quick-lru": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==" - }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", - "dev": true, - "requires": { - "@babel/highlight": "^7.18.6" - } - }, - "@babel/compat-data": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", - "integrity": "sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==", - "dev": true - }, - "@babel/core": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.4.tgz", - "integrity": "sha512-qt/YV149Jman/6AfmlxJ04LMIu8bMoyl3RB91yTFrxQmgbrSvQMy7cI8Q62FHx1t8wJ8B5fu0UDoLwHAhUo1QA==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-compilation-targets": "^7.21.4", - "@babel/helper-module-transforms": "^7.21.2", - "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.4", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.4", - "@babel/types": "^7.21.4", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", - "semver": "^6.3.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", - "dev": true, - "requires": { - "@babel/types": "^7.21.4", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz", - "integrity": "sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.21.4", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", - "lru-cache": "^5.1.1", - "semver": "^6.3.0" - }, - "dependencies": { - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true - } - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", - "dev": true - }, - "@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.21.4" - } - }, - "@babel/helper-module-transforms": { - "version": "7.21.2", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz", - "integrity": "sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.20.2", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.2", - "@babel/types": "^7.21.2" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", - "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", - "dev": true - }, - "@babel/helper-simple-access": { - "version": "7.20.2", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz", - "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==", - "dev": true, - "requires": { - "@babel/types": "^7.20.2" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "dev": true, - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", - "dev": true - }, - "@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", - "dev": true - }, - "@babel/helpers": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.0.tgz", - "integrity": "sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==", - "dev": true, - "requires": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.0", - "@babel/types": "^7.21.0" - } - }, - "@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", - "dev": true - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-bigint": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", - "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-import-meta": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", - "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-jsx": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", - "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-typescript": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", - "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.20.2" - } - }, - "@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" - } - }, - "@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", - "to-fast-properties": "^2.0.0" - } - }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true - }, - "@esbuild/android-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.18.tgz", - "integrity": "sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw==", - "dev": true, - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz", - "integrity": "sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw==", - "dev": true, - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.18.tgz", - "integrity": "sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz", - "integrity": "sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ==", - "dev": true, - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz", - "integrity": "sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz", - "integrity": "sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA==", - "dev": true, - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz", - "integrity": "sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz", - "integrity": "sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg==", - "dev": true, - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz", - "integrity": "sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz", - "integrity": "sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz", - "integrity": "sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz", - "integrity": "sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz", - "integrity": "sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ==", - "dev": true, - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz", - "integrity": "sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA==", - "dev": true, - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz", - "integrity": "sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw==", - "dev": true, - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz", - "integrity": "sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA==", - "dev": true, - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz", - "integrity": "sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg==", - "dev": true, - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz", - "integrity": "sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA==", - "dev": true, - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz", - "integrity": "sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz", - "integrity": "sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg==", - "dev": true, - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz", - "integrity": "sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw==", - "dev": true, - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz", - "integrity": "sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg==", - "dev": true, - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^3.3.0" - } - }, - "@eslint-community/regexpp": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", - "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.5.1", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - } - }, - "@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", - "dev": true - }, - "@humanwhocodes/config-array": { - "version": "0.11.8", - "dev": true, - "requires": { - "@humanwhocodes/object-schema": "^1.2.1", - "debug": "^4.1.1", - "minimatch": "^3.0.5" - } - }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "dev": true - }, - "@humanwhocodes/object-schema": { - "version": "1.2.1", - "dev": true - }, - "@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "requires": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true - }, - "@jest/console": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", - "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/core": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", - "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/reporters": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "jest-changed-files": "^29.5.0", - "jest-config": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-resolve-dependencies": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "jest-watcher": "^29.5.0", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/create-cache-key-function": { - "version": "27.4.2", - "dev": true, - "requires": { - "@jest/types": "^27.4.2" - } - }, - "@jest/environment": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", - "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", - "dev": true, - "requires": { - "expect": "^29.5.0", - "jest-snapshot": "^29.5.0" - } - }, - "@jest/expect-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", - "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3" - } - }, - "@jest/fake-timers": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", - "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@sinonjs/fake-timers": "^10.0.2", - "@types/node": "*", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/globals": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", - "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/types": "^29.5.0", - "jest-mock": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/reporters": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", - "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", - "dev": true, - "requires": { - "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "@types/node": "*", - "chalk": "^4.0.0", - "collect-v8-coverage": "^1.0.0", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-instrument": "^5.1.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.1.3", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "slash": "^3.0.0", - "string-length": "^4.0.1", - "strip-ansi": "^6.0.0", - "v8-to-istanbul": "^9.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/schemas": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", - "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", - "dev": true, - "requires": { - "@sinclair/typebox": "^0.25.16" - } - }, - "@jest/source-map": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", - "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.15", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" - } - }, - "@jest/test-result": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", - "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/istanbul-lib-coverage": "^2.0.0", - "collect-v8-coverage": "^1.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/test-sequencer": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", - "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "slash": "^3.0.0" - } - }, - "@jest/transform": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", - "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/types": "^29.5.0", - "@jridgewell/trace-mapping": "^0.3.15", - "babel-plugin-istanbul": "^6.1.1", - "chalk": "^4.0.0", - "convert-source-map": "^2.0.0", - "fast-json-stable-stringify": "^2.1.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "micromatch": "^4.0.4", - "pirates": "^4.0.4", - "slash": "^3.0.0", - "write-file-atomic": "^4.0.2" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "@jest/types": { - "version": "27.5.1", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^16.0.0", - "chalk": "^4.0.0" - } - }, - "@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" - }, - "@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==" - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", - "requires": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" - }, - "dependencies": { - "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" - } - } - }, - "@mole-inc/bin-wrapper": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@mole-inc/bin-wrapper/-/bin-wrapper-8.0.1.tgz", - "integrity": "sha512-sTGoeZnjI8N4KS+sW2AN95gDBErhAguvkw/tWdCjeM8bvxpz5lqrnd0vOJABA1A+Ic3zED7PYoLP/RANLgVotA==", - "dev": true, - "requires": { - "bin-check": "^4.1.0", - "bin-version-check": "^5.0.0", - "content-disposition": "^0.5.4", - "ext-name": "^5.0.0", - "file-type": "^17.1.6", - "filenamify": "^5.0.2", - "got": "^11.8.5", - "os-filter-obj": "^2.0.0" - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5" - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true - }, - "@sinclair/typebox": { - "version": "0.25.24", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", - "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", - "dev": true - }, - "@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", - "dev": true - }, - "@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "dev": true, - "requires": { - "type-detect": "4.0.8" - } - }, - "@sinonjs/fake-timers": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", - "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", - "dev": true, - "requires": { - "@sinonjs/commons": "^2.0.0" - } - }, - "@swc/cli": { - "version": "0.1.62", - "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.1.62.tgz", - "integrity": "sha512-kOFLjKY3XH1DWLfXL1/B5MizeNorHR8wHKEi92S/Zi9Md/AK17KSqR8MgyRJ6C1fhKHvbBCl8wboyKAFXStkYw==", - "dev": true, - "requires": { - "@mole-inc/bin-wrapper": "^8.0.1", - "commander": "^7.1.0", - "fast-glob": "^3.2.5", - "semver": "^7.3.8", - "slash": "3.0.0", - "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "dev": true - } - } - }, - "@swc/core": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.55.tgz", - "integrity": "sha512-w/lN3OuJsuy868yJZKop+voZLVzI5pVSoopQVtgDNkEzejnPuRp9XaeAValvuMaWqKoTMtOjLzEPyv/xiAGYQQ==", - "dev": true, - "requires": { - "@swc/core-darwin-arm64": "1.3.55", - "@swc/core-darwin-x64": "1.3.55", - "@swc/core-linux-arm-gnueabihf": "1.3.55", - "@swc/core-linux-arm64-gnu": "1.3.55", - "@swc/core-linux-arm64-musl": "1.3.55", - "@swc/core-linux-x64-gnu": "1.3.55", - "@swc/core-linux-x64-musl": "1.3.55", - "@swc/core-win32-arm64-msvc": "1.3.55", - "@swc/core-win32-ia32-msvc": "1.3.55", - "@swc/core-win32-x64-msvc": "1.3.55" - } - }, - "@swc/core-darwin-arm64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.55.tgz", - "integrity": "sha512-UnHC8aPg/JvHhgXxTU6EhTtfnYNS7nhq8EKB8laNPxlHbwEyMBVQ2QuJHlNCtFtvSfX/uH5l04Ld1iGXnBTfdQ==", - "dev": true, - "optional": true - }, - "@swc/core-darwin-x64": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.55.tgz", - "integrity": "sha512-VNJkFVARrktIqtaLrD1NFA54gqekH7eAUcUY2U2SdHwO67HYjfMXMxlugLP5PDasSKpTkrVooUdhkffoA5W50g==", - "dev": true, - "optional": true - }, - "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.55.tgz", - "integrity": "sha512-6OcohhIFKKNW/TpJt26Tpul8zyL7dmp1Lnyj2BX9ycsZZ5UnsNiGqn37mrqJgVTx/ansEmbyOmKu2mzm/Ct6cQ==", - "dev": true, - "optional": true - }, - "@swc/core-linux-arm64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.55.tgz", - "integrity": "sha512-MfZtXGBv21XWwvrSMP0CMxScDolT/iv5PRl9UBprYUehwWr7BNjA3V9W7QQ+kKoPyORWk7LX7OpJZF3FnO618Q==", - "dev": true, - "optional": true - }, - "@swc/core-linux-arm64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.55.tgz", - "integrity": "sha512-iZJo+7L5lv10W0f0C6SlyteAyMJt5Tp+aH3+nlAwKdtc+VjyL1sGhR8DJMXp2/buBRZJ9tjEtpXKDaWUdSdF7Q==", - "dev": true, - "optional": true - }, - "@swc/core-linux-x64-gnu": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.55.tgz", - "integrity": "sha512-Rmc8ny/mslzzz0+wNK9/mLdyAWVbMZHRSvljhpzASmq48NBkmZ5vk9/WID6MnUz2e9cQ0JxJQs8t39KlFJtW3g==", - "dev": true, - "optional": true - }, - "@swc/core-linux-x64-musl": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.55.tgz", - "integrity": "sha512-Ymoc4xxINzS93ZjVd2UZfLZk1jF6wHjdCbC1JF+0zK3IrNrxCIDoWoaAj0+Bbvyo3hD1Xg/cneSTsqX8amnnuQ==", - "dev": true, - "optional": true - }, - "@swc/core-win32-arm64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.55.tgz", - "integrity": "sha512-OhnmFstq2qRU2GI5I0G/8L+vc2rx8+w+IOA6EZBrY4FuMCbPIZKKzlnAIxYn2W+yD4gvBzYP3tgEcaDfQk6EkA==", - "dev": true, - "optional": true - }, - "@swc/core-win32-ia32-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.55.tgz", - "integrity": "sha512-3VR5rHZ6uoL/Vo3djV30GgX2oyDwWWsk+Yp+nyvYyBaKYiH2zeHfxdYRLSQV3W7kSlCAH3oDYpSljrWZ0t5XEQ==", - "dev": true, - "optional": true - }, - "@swc/core-win32-x64-msvc": { - "version": "1.3.55", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.55.tgz", - "integrity": "sha512-KBtMFtRwnbxBugYf6i2ePqEGdxsk715KcqGMjGhxNg7BTACnXnhj37irHu2e7A7wZffbkUVUYuj/JEgVkEjSxg==", - "dev": true, - "optional": true - }, - "@swc/jest": { - "version": "0.2.26", - "resolved": "https://registry.npmjs.org/@swc/jest/-/jest-0.2.26.tgz", - "integrity": "sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A==", - "dev": true, - "requires": { - "@jest/create-cache-key-function": "^27.4.2", - "jsonc-parser": "^3.2.0" - } - }, - "@swc/register": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/@swc/register/-/register-0.1.10.tgz", - "integrity": "sha512-6STwH/q4dc3pitXLVkV7sP0Hiy+zBsU2wOF1aXpXR95pnH3RYHKIsDC+gvesfyB7jxNT9OOZgcqOp9RPxVTx9A==", - "dev": true, - "requires": { - "lodash.clonedeep": "^4.5.0", - "pirates": "^4.0.1", - "source-map-support": "^0.5.13" - } - }, - "@szmarczak/http-timer": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", - "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", - "dev": true, - "requires": { - "defer-to-connect": "^2.0.0" - } - }, - "@tokenizer/token": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", - "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==", - "dev": true - }, - "@trysound/sax": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", - "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", - "dev": true - }, - "@types/babel__core": { - "version": "7.20.0", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", - "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", - "dev": true, - "requires": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.18.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", - "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/cacheable-request": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", - "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", - "dev": true, - "requires": { - "@types/http-cache-semantics": "*", - "@types/keyv": "^3.1.4", - "@types/node": "*", - "@types/responselike": "^1.0.0" - } - }, - "@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", - "dev": true - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.3", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "3.0.0", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "3.0.1", - "dev": true, - "requires": { - "@types/istanbul-lib-report": "*" - } - }, - "@types/keyv": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", - "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/node": { - "version": "16.10.2", - "dev": true - }, - "@types/prettier": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", - "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", - "dev": true - }, - "@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", - "dev": true, - "requires": { - "@types/node": "*" - } - }, - "@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", - "dev": true - }, - "@types/yargs": { - "version": "16.0.4", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "20.2.1", - "dev": true - }, - "acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-regex": { - "version": "5.0.1", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==" - }, - "anymatch": { - "version": "3.1.2", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "arch": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", - "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", - "dev": true - }, - "arg": { - "version": "5.0.2" - }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "babel-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", - "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", - "dev": true, - "requires": { - "@jest/transform": "^29.5.0", - "@types/babel__core": "^7.1.14", - "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^29.5.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "slash": "^3.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", - "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^5.0.4", - "test-exclude": "^6.0.0" - } - }, - "babel-plugin-jest-hoist": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", - "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", - "dev": true, - "requires": { - "@babel/template": "^7.3.3", - "@babel/types": "^7.3.3", - "@types/babel__core": "^7.1.14", - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", - "dev": true, - "requires": { - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" - } - }, - "babel-preset-jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", - "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", - "dev": true, - "requires": { - "babel-plugin-jest-hoist": "^29.5.0", - "babel-preset-current-node-syntax": "^1.0.0" - } - }, - "balanced-match": { - "version": "1.0.0" - }, - "bin-check": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bin-check/-/bin-check-4.1.0.tgz", - "integrity": "sha512-b6weQyEUKsDGFlACWSIOfveEnImkJyK/FGW6FAG42loyoquvjdtOIqO6yBFzHyqyVVhNgNkQxxx09SFLK28YnA==", - "dev": true, - "requires": { - "execa": "^0.7.0", - "executable": "^4.1.0" - } - }, - "bin-version": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bin-version/-/bin-version-6.0.0.tgz", - "integrity": "sha512-nk5wEsP4RiKjG+vF+uG8lFsEn4d7Y6FVDamzzftSunXOoOcOOkzcWdKVlGgFFwlUQCj63SgnUkLLGF8v7lufhw==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "find-versions": "^5.0.0" - }, - "dependencies": { - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - } - } - }, - "bin-version-check": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bin-version-check/-/bin-version-check-5.0.0.tgz", - "integrity": "sha512-Q3FMQnS5eZmrBGqmDXLs4dbAn/f+52voP6ykJYmweSA60t6DyH4UTSwZhtbK5UH+LBoWvDljILUQMLRUtsynsA==", - "dev": true, - "requires": { - "bin-version": "^6.0.0", - "semver": "^7.3.5", - "semver-truncate": "^2.0.0" - } - }, - "binary-extensions": { - "version": "2.2.0" - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "dev": true - }, - "cacheable-lookup": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", - "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", - "dev": true - }, - "cacheable-request": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", - "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", - "dev": true, - "requires": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^4.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^6.0.1", - "responselike": "^2.0.0" - }, - "dependencies": { - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - } - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "camelcase-css": { - "version": "2.0.1" - }, - "caniuse-api": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", - "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", - "dev": true, - "requires": { - "browserslist": "^4.0.0", - "caniuse-lite": "^1.0.0", - "lodash.memoize": "^4.1.2", - "lodash.uniq": "^4.5.0" - } - }, - "caniuse-lite": { - "version": "1.0.30001481", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz", - "integrity": "sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ==", - "dev": true - }, - "chalk": { - "version": "4.1.2", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", - "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true - }, - "chokidar": { - "version": "3.5.3", - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-number": { - "version": "7.0.0" - }, - "to-regex-range": { - "version": "5.0.1", - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", - "dev": true - }, - "cjs-module-lexer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", - "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", - "dev": true - }, - "cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - } - }, - "clone-response": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", - "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", - "dev": true, - "requires": { - "mimic-response": "^1.0.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", - "dev": true - }, - "collect-v8-coverage": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", - "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", - "dev": true - }, - "color-convert": { - "version": "2.0.1", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "dev": true - }, - "colord": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", - "integrity": "sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==", - "dev": true - }, - "commander": { - "version": "7.2.0", - "dev": true - }, - "concat-map": { - "version": "0.0.1" - }, - "concurrently": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-8.0.1.tgz", - "integrity": "sha512-Sh8bGQMEL0TAmAm2meAXMjcASHZa7V0xXQVDBLknCPa9TPtkY9yYs+0cnGGgfdkW0SV1Mlg+hVGfXcoI8d3MJA==", - "dev": true, - "requires": { - "chalk": "^4.1.2", - "date-fns": "^2.29.3", - "lodash": "^4.17.21", - "rxjs": "^7.8.0", - "shell-quote": "^1.8.0", - "spawn-command": "0.0.2-1", - "supports-color": "^8.1.1", - "tree-kill": "^1.2.2", - "yargs": "^17.7.1" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "dev": true, - "requires": { - "safe-buffer": "5.2.1" - } - }, - "convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-declaration-sorter": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.4.0.tgz", - "integrity": "sha512-jDfsatwWMWN0MODAFuHszfjphEXfNw9JUAhmY4pLu3TyTU+ohUpsbVtbU+1MZn4a47D9kqh03i4eyOm+74+zew==", - "dev": true, - "requires": {} - }, - "css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - } - }, - "css-tree": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", - "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", - "dev": true, - "requires": { - "mdn-data": "2.0.30", - "source-map-js": "^1.0.1" - } - }, - "css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true - }, - "cssesc": { - "version": "3.0.0" - }, - "cssnano": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.0.tgz", - "integrity": "sha512-RGlcbzGhzEBCHuQe3k+Udyj5M00z0pm9S+VurHXFEOXxH+y0sVrJH2sMzoyz2d8N1EScazg+DVvmgyx0lurwwA==", - "dev": true, - "requires": { - "cssnano-preset-default": "^6.0.0", - "lilconfig": "^2.1.0" - } - }, - "cssnano-preset-default": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.0.tgz", - "integrity": "sha512-BDxlaFzObRDXUiCCBQUNQcI+f1/aX2mgoNtXGjV6PG64POcHoDUoX+LgMWw+Q4609QhxwkcSnS65YFs42RA6qQ==", - "dev": true, - "requires": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^8.2.3", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.0", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - } - }, - "cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "requires": {} - }, - "csso": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", - "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", - "dev": true, - "requires": { - "css-tree": "~2.2.0" - }, - "dependencies": { - "css-tree": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", - "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", - "dev": true, - "requires": { - "mdn-data": "2.0.28", - "source-map-js": "^1.0.1" - } - }, - "mdn-data": { - "version": "2.0.28", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", - "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", - "dev": true - } - } - }, - "date-fns": { - "version": "2.29.3", - "dev": true - }, - "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "requires": { - "mimic-response": "^3.1.0" - }, - "dependencies": { - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true - } - } - }, - "dedent": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", - "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "dev": true - }, - "deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true - }, - "defer-to-connect": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", - "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", - "dev": true - }, - "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true - }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", - "dev": true - }, - "didyoumean": { - "version": "1.2.2" - }, - "diff-sequences": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", - "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", - "dev": true - }, - "dlv": { - "version": "1.1.3" - }, - "doctrine": { - "version": "3.0.0", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - } - }, - "domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true - }, - "domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "requires": { - "domelementtype": "^2.3.0" - } - }, - "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", - "dev": true, - "requires": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" - } - }, - "electron-to-chromium": { - "version": "1.4.371", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz", - "integrity": "sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw==", - "dev": true - }, - "emittery": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", - "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "esbuild": { - "version": "0.17.18", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.18.tgz", - "integrity": "sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w==", - "dev": true, - "requires": { - "@esbuild/android-arm": "0.17.18", - "@esbuild/android-arm64": "0.17.18", - "@esbuild/android-x64": "0.17.18", - "@esbuild/darwin-arm64": "0.17.18", - "@esbuild/darwin-x64": "0.17.18", - "@esbuild/freebsd-arm64": "0.17.18", - "@esbuild/freebsd-x64": "0.17.18", - "@esbuild/linux-arm": "0.17.18", - "@esbuild/linux-arm64": "0.17.18", - "@esbuild/linux-ia32": "0.17.18", - "@esbuild/linux-loong64": "0.17.18", - "@esbuild/linux-mips64el": "0.17.18", - "@esbuild/linux-ppc64": "0.17.18", - "@esbuild/linux-riscv64": "0.17.18", - "@esbuild/linux-s390x": "0.17.18", - "@esbuild/linux-x64": "0.17.18", - "@esbuild/netbsd-x64": "0.17.18", - "@esbuild/openbsd-x64": "0.17.18", - "@esbuild/sunos-x64": "0.17.18", - "@esbuild/win32-arm64": "0.17.18", - "@esbuild/win32-ia32": "0.17.18", - "@esbuild/win32-x64": "0.17.18" - } - }, - "escalade": { - "version": "3.1.1", - "dev": true - }, - "escape-string-regexp": { - "version": "4.0.0", - "dev": true - }, - "eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", - "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0" - }, - "dependencies": { - "find-up": { - "version": "5.0.0", - "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "6.0.0", - "dev": true, - "requires": { - "p-locate": "^5.0.0" - } - }, - "p-locate": { - "version": "5.0.0", - "dev": true, - "requires": { - "p-limit": "^3.0.2" - } - } - } - }, - "eslint-config-prettier": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", - "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", - "dev": true, - "requires": {} - }, - "eslint-plugin-prettier": { - "version": "4.2.1", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - } - }, - "eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", - "dev": true - }, - "espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", - "dev": true, - "requires": { - "acorn": "^8.8.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - } - }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "dev": true - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha512-RztN09XglpYI7aBBrJCPW95jEH7YF1UEPOoX9yDhUTPdp7mK+CQvnLTuD10BNXZ3byLTu2uehZ8EcKT/4CGiFw==", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==", - "dev": true - } - } - }, - "executable": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", - "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", - "dev": true, - "requires": { - "pify": "^2.2.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", - "dev": true - }, - "expect": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", - "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", - "dev": true, - "requires": { - "@jest/expect-utils": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0" - } - }, - "ext-list": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", - "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", - "dev": true, - "requires": { - "mime-db": "^1.28.0" - } - }, - "ext-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", - "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", - "dev": true, - "requires": { - "ext-list": "^2.0.0", - "sort-keys-length": "^1.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "dev": true - }, - "fast-glob": { - "version": "3.2.12", - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "requires": { - "is-glob": "^4.0.1" - } - } - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "dev": true - }, - "fastq": { - "version": "1.11.0", - "requires": { - "reusify": "^1.0.4" - } - }, - "fb-watchman": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", - "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", - "dev": true, - "requires": { - "bser": "2.1.1" - } - }, - "file-entry-cache": { - "version": "6.0.1", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-type": { - "version": "17.1.6", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-17.1.6.tgz", - "integrity": "sha512-hlDw5Ev+9e883s0pwUsuuYNu4tD7GgpUnOvykjv1Gya0ZIjuKumthDRua90VUn6/nlRKAjcxLUnHNTIUWwWIiw==", - "dev": true, - "requires": { - "readable-web-to-node-stream": "^3.0.2", - "strtok3": "^7.0.0-alpha.9", - "token-types": "^5.0.0-alpha.2" - } - }, - "filename-reserved-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-3.0.0.tgz", - "integrity": "sha512-hn4cQfU6GOT/7cFHXBqeBg2TbrMBgdD0kcjLhvSQYYwm3s4B6cjvBfb7nBALJLAXqmU5xajSa7X2NnUud/VCdw==", - "dev": true - }, - "filenamify": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-5.1.1.tgz", - "integrity": "sha512-M45CbrJLGACfrPOkrTp3j2EcO9OBkKUYME0eiqOCa7i2poaklU0jhlIaMlr8ijLorT0uLAzrn3qXOp5684CkfA==", - "dev": true, - "requires": { - "filename-reserved-regex": "^3.0.0", - "strip-outer": "^2.0.0", - "trim-repeated": "^2.0.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "find-versions": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-5.1.0.tgz", - "integrity": "sha512-+iwzCJ7C5v5KgcBuueqVoNiHVoQpwiUK5XFLjf0affFTep+Wcw93tPvmb8tqujDNmzhBDPddnWV/qgWSXgq+Hg==", - "dev": true, - "requires": { - "semver-regex": "^4.0.5" - } - }, - "flat-cache": { - "version": "3.0.4", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "flatted": { - "version": "3.1.1", - "dev": true - }, - "foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "dependencies": { - "signal-exit": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", - "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", - "dev": true - } - } - }, - "fraction.js": { - "version": "4.2.0", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0" - }, - "fsevents": { - "version": "2.3.2", - "optional": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==", - "dev": true - }, - "glob": { - "version": "7.1.6", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "6.0.2", - "requires": { - "is-glob": "^4.0.3" - } - }, - "globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "got": { - "version": "11.8.6", - "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", - "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", - "dev": true, - "requires": { - "@sindresorhus/is": "^4.0.0", - "@szmarczak/http-timer": "^4.0.5", - "@types/cacheable-request": "^6.0.1", - "@types/responselike": "^1.0.0", - "cacheable-lookup": "^5.0.3", - "cacheable-request": "^7.0.2", - "decompress-response": "^6.0.0", - "http2-wrapper": "^1.0.0-beta.5.2", - "lowercase-keys": "^2.0.0", - "p-cancelable": "^2.0.0", - "responselike": "^2.0.0" - } - }, - "graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true - }, - "grapheme-splitter": { - "version": "1.0.4", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "4.0.0", - "dev": true - }, - "html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "dev": true - }, - "http2-wrapper": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", - "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", - "dev": true, - "requires": { - "quick-lru": "^5.1.1", - "resolve-alpn": "^1.0.0" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, - "ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "dev": true - }, - "inflight": { - "version": "1.0.6", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true - }, - "is-binary-path": { - "version": "2.1.0", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.0.tgz", - "integrity": "sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==", - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-path-inside": { - "version": "3.0.3", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", - "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", - "dev": true, - "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" - } - }, - "istanbul-lib-source-maps": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", - "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0", - "source-map": "^0.6.1" - } - }, - "istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", - "dev": true, - "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - } - }, - "jackspeak": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", - "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", - "dev": true, - "requires": { - "@pkgjs/parseargs": "^0.11.0", - "cliui": "^7.0.4" - }, - "dependencies": { - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - } - } - }, - "jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", - "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/types": "^29.5.0", - "import-local": "^3.0.2", - "jest-cli": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-changed-files": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", - "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", - "dev": true, - "requires": { - "execa": "^5.0.0", - "p-limit": "^3.1.0" - }, - "dependencies": { - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - } - } - }, - "jest-circus": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", - "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/expect": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "dedent": "^0.7.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^29.5.0", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "p-limit": "^3.1.0", - "pretty-format": "^29.5.0", - "pure-rand": "^6.0.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-cli": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", - "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", - "dev": true, - "requires": { - "@jest/core": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "exit": "^0.1.2", - "graceful-fs": "^4.2.9", - "import-local": "^3.0.2", - "jest-config": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "prompts": "^2.0.1", - "yargs": "^17.3.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-config": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", - "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@jest/test-sequencer": "^29.5.0", - "@jest/types": "^29.5.0", - "babel-jest": "^29.5.0", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-circus": "^29.5.0", - "jest-environment-node": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-runner": "^29.5.0", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "micromatch": "^4.0.4", - "parse-json": "^5.2.0", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-diff": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", - "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.4.3", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-docblock": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", - "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", - "dev": true, - "requires": { - "detect-newline": "^3.0.0" - } - }, - "jest-each": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", - "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "jest-util": "^29.5.0", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-environment-node": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", - "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-mock": "^29.5.0", - "jest-util": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-get-type": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", - "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", - "dev": true - }, - "jest-haste-map": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", - "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/graceful-fs": "^4.1.3", - "@types/node": "*", - "anymatch": "^3.0.3", - "fb-watchman": "^2.0.0", - "fsevents": "^2.3.2", - "graceful-fs": "^4.2.9", - "jest-regex-util": "^29.4.3", - "jest-util": "^29.5.0", - "jest-worker": "^29.5.0", - "micromatch": "^4.0.4", - "walker": "^1.0.8" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-leak-detector": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", - "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", - "dev": true, - "requires": { - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-matcher-utils": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", - "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "pretty-format": "^29.5.0" - } - }, - "jest-message-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", - "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.5.0", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.5.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-mock": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", - "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "jest-util": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-pnp-resolver": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", - "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} - }, - "jest-regex-util": { - "version": "29.4.3", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", - "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", - "dev": true - }, - "jest-resolve": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", - "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-pnp-resolver": "^1.2.2", - "jest-util": "^29.5.0", - "jest-validate": "^29.5.0", - "resolve": "^1.20.0", - "resolve.exports": "^2.0.0", - "slash": "^3.0.0" - } - }, - "jest-resolve-dependencies": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", - "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", - "dev": true, - "requires": { - "jest-regex-util": "^29.4.3", - "jest-snapshot": "^29.5.0" - } - }, - "jest-runner": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", - "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", - "dev": true, - "requires": { - "@jest/console": "^29.5.0", - "@jest/environment": "^29.5.0", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "graceful-fs": "^4.2.9", - "jest-docblock": "^29.4.3", - "jest-environment-node": "^29.5.0", - "jest-haste-map": "^29.5.0", - "jest-leak-detector": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-resolve": "^29.5.0", - "jest-runtime": "^29.5.0", - "jest-util": "^29.5.0", - "jest-watcher": "^29.5.0", - "jest-worker": "^29.5.0", - "p-limit": "^3.1.0", - "source-map-support": "0.5.13" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "source-map-support": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", - "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - } - } - }, - "jest-runtime": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", - "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", - "dev": true, - "requires": { - "@jest/environment": "^29.5.0", - "@jest/fake-timers": "^29.5.0", - "@jest/globals": "^29.5.0", - "@jest/source-map": "^29.4.3", - "@jest/test-result": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "cjs-module-lexer": "^1.0.0", - "collect-v8-coverage": "^1.0.0", - "glob": "^7.1.3", - "graceful-fs": "^4.2.9", - "jest-haste-map": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-mock": "^29.5.0", - "jest-regex-util": "^29.4.3", - "jest-resolve": "^29.5.0", - "jest-snapshot": "^29.5.0", - "jest-util": "^29.5.0", - "slash": "^3.0.0", - "strip-bom": "^4.0.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-snapshot": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", - "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", - "dev": true, - "requires": { - "@babel/core": "^7.11.6", - "@babel/generator": "^7.7.2", - "@babel/plugin-syntax-jsx": "^7.7.2", - "@babel/plugin-syntax-typescript": "^7.7.2", - "@babel/traverse": "^7.7.2", - "@babel/types": "^7.3.3", - "@jest/expect-utils": "^29.5.0", - "@jest/transform": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/babel__traverse": "^7.0.6", - "@types/prettier": "^2.1.5", - "babel-preset-current-node-syntax": "^1.0.0", - "chalk": "^4.0.0", - "expect": "^29.5.0", - "graceful-fs": "^4.2.9", - "jest-diff": "^29.5.0", - "jest-get-type": "^29.4.3", - "jest-matcher-utils": "^29.5.0", - "jest-message-util": "^29.5.0", - "jest-util": "^29.5.0", - "natural-compare": "^1.4.0", - "pretty-format": "^29.5.0", - "semver": "^7.3.5" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-util": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", - "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-validate": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", - "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", - "dev": true, - "requires": { - "@jest/types": "^29.5.0", - "camelcase": "^6.2.0", - "chalk": "^4.0.0", - "jest-get-type": "^29.4.3", - "leven": "^3.1.0", - "pretty-format": "^29.5.0" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true - } - } - }, - "jest-watcher": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", - "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", - "dev": true, - "requires": { - "@jest/test-result": "^29.5.0", - "@jest/types": "^29.5.0", - "@types/node": "*", - "ansi-escapes": "^4.2.1", - "chalk": "^4.0.0", - "emittery": "^0.13.1", - "jest-util": "^29.5.0", - "string-length": "^4.0.1" - }, - "dependencies": { - "@jest/types": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", - "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - } - }, - "@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - } - } - }, - "jest-worker": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", - "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", - "dev": true, - "requires": { - "@types/node": "*", - "jest-util": "^29.5.0", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "jiti": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", - "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" - }, - "js-sdsl": { - "version": "4.1.4", - "dev": true - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "requires": { - "argparse": "^2.0.1" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "dev": true - }, - "json5": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", - "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0", - "dev": true - }, - "keyv": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", - "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", - "dev": true, - "requires": { - "json-buffer": "3.0.1" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.4.1", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "dependencies": { - "prelude-ls": { - "version": "1.2.1", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - } - } - }, - "lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3", - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" - } - }, - "lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", - "dev": true, - "optional": true - }, - "lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", - "dev": true, - "optional": true - }, - "lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", - "dev": true, - "optional": true - }, - "lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", - "dev": true, - "optional": true - }, - "lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", - "dev": true, - "optional": true - }, - "lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", - "dev": true, - "optional": true - }, - "lilconfig": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==" - }, - "lines-and-columns": { - "version": "1.2.4" - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash": { - "version": "4.17.21", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "dev": true - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true - }, - "lodash.merge": { - "version": "4.6.2", - "dev": true - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", - "dev": true - }, - "lowercase-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", - "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "makeerror": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", - "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", - "dev": true, - "requires": { - "tmpl": "1.0.5" - } - }, - "mdn-data": { - "version": "2.0.30", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", - "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "merge2": { - "version": "1.4.1" - }, - "micromatch": { - "version": "4.0.5", - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0" - }, - "to-regex-range": { - "version": "5.0.1", - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "dev": true - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==" - }, - "natural-compare": { - "version": "1.4.0", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true - }, - "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==", - "dev": true - }, - "normalize-path": { - "version": "3.0.0" - }, - "normalize-range": { - "version": "0.1.2", - "dev": true - }, - "normalize-url": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", - "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", - "dev": true - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", - "dev": true, - "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", - "dev": true - } - } - }, - "nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "object-assign": { - "version": "4.1.1" - }, - "object-hash": { - "version": "3.0.0" - }, - "once": { - "version": "1.4.0", - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "optionator": { - "version": "0.9.1", - "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "dependencies": { - "prelude-ls": { - "version": "1.2.1", - "dev": true - }, - "type-check": { - "version": "0.4.0", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1" - } - } - } - }, - "os-filter-obj": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/os-filter-obj/-/os-filter-obj-2.0.0.tgz", - "integrity": "sha512-uksVLsqG3pVdzzPvmAHpBK0wKxYItuzZr7SziusRPoz67tGV8rL1szZ6IdeUrbqLjGDwApBtN29eEE3IqGHOjg==", - "dev": true, - "requires": { - "arch": "^2.1.0" - } - }, - "p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", - "dev": true - }, - "p-limit": { - "version": "3.1.0", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - }, - "dependencies": { - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - } - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "requires": { - "callsites": "^3.0.0" - } - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1" - }, - "path-key": { - "version": "3.1.1", - "dev": true - }, - "path-parse": { - "version": "1.0.7" - }, - "path-scurry": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", - "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", - "dev": true, - "requires": { - "lru-cache": "^9.0.0", - "minipass": "^5.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", - "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", - "dev": true - } - } - }, - "peek-readable": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-5.0.0.tgz", - "integrity": "sha512-YtCKvLUOvwtMGmrniQPdO7MwPjgkFBtFIrmfSbYmYuq3tKDV/mcfAhBth1+C3ru7uXIZasc/pHnb+YDYNkkj4A==", - "dev": true - }, - "picocolors": { - "version": "1.0.0" - }, - "picomatch": { - "version": "2.3.1" - }, - "pify": { - "version": "2.3.0" - }, - "pirates": { - "version": "4.0.4" - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", - "requires": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" - } - }, - "postcss-calc": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.2.4.tgz", - "integrity": "sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.9", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "requires": {} - }, - "postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "requires": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - } - }, - "postcss-js": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "requires": { - "camelcase-css": "^2.0.1" - } - }, - "postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", - "requires": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" - }, - "dependencies": { - "yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==" - } - } - }, - "postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - } - }, - "postcss-merge-rules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.0.tgz", - "integrity": "sha512-rCXkklftzEkniyv3f4mRCQzxD6oE4Quyh61uyWTUbCJ26Pv2hoz+fivJSsSBWxDBeScR4fKCfF3HHTcD7Ybqnw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-nested": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", - "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", - "requires": { - "postcss-selector-parser": "^6.0.11" - } - }, - "postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "requires": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-selector-parser": { - "version": "6.0.11", - "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - } - }, - "postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - } - }, - "postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-value-parser": { - "version": "4.2.0" - }, - "prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true - }, - "prettier-linter-helpers": { - "version": "1.0.0", - "dev": true, - "requires": { - "fast-diff": "^1.1.2" - } - }, - "pretty-format": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", - "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", - "dev": true, - "requires": { - "@jest/schemas": "^29.4.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true - } - } - }, - "prompts": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", - "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.5" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true - }, - "pure-rand": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.2.tgz", - "integrity": "sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3" - }, - "quick-lru": { - "version": "5.1.1", - "dev": true - }, - "react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "read-cache": { - "version": "1.0.0", - "requires": { - "pify": "^2.3.0" - } - }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readable-web-to-node-stream": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", - "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", - "dev": true, - "requires": { - "readable-stream": "^3.6.0" - } - }, - "readdirp": { - "version": "3.6.0", - "requires": { - "picomatch": "^2.2.1" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true - }, - "resolve": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz", - "integrity": "sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==", - "requires": { - "is-core-module": "^2.11.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-alpn": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", - "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", - "dev": true - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } - } - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "resolve.exports": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", - "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", - "dev": true - }, - "responselike": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", - "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", - "dev": true, - "requires": { - "lowercase-keys": "^2.0.0" - } - }, - "reusify": { - "version": "1.0.4" - }, - "rimraf": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.0.tgz", - "integrity": "sha512-Jf9llaP+RvaEVS5nPShYFhtXIrb3LRKP281ib3So0KkeZKo2wIKyq0Re7TOSwanasA423PSr6CCIL4bP6T040g==", - "dev": true, - "requires": { - "glob": "^10.0.0" - }, - "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "glob": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", - "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", - "dev": true, - "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.0", - "minipass": "^5.0.0", - "path-scurry": "^1.7.0" - } - }, - "minimatch": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", - "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } - } - }, - "run-parallel": { - "version": "1.2.0", - "requires": { - "queue-microtask": "^1.2.2" - } - }, - "rxjs": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz", - "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==", - "dev": true, - "requires": { - "tslib": "^2.1.0" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, - "semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "semver-regex": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-4.0.5.tgz", - "integrity": "sha512-hunMQrEy1T6Jr2uEVjrAIqjwWcQTgOAcIM52C8MY1EZSD3DDNft04XzvYKPqjED65bNVVko0YI38nYeEHCX3yw==", - "dev": true - }, - "semver-truncate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-truncate/-/semver-truncate-2.0.0.tgz", - "integrity": "sha512-Rh266MLDYNeML5h90ttdMwfXe1+Nc4LAWd9X1KdJe8pPHP4kFmvLZALtsMNHNdvTyQygbEC0D59sIz47DIaq8w==", - "dev": true, - "requires": { - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "shebang-command": { - "version": "2.0.0", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "dev": true - }, - "shell-quote": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", - "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", - "dev": true - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "sisteransi": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", - "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true - }, - "slash": { - "version": "3.0.0", - "dev": true - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==", - "dev": true, - "requires": { - "is-plain-obj": "^1.0.0" - } - }, - "sort-keys-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", - "integrity": "sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==", - "dev": true, - "requires": { - "sort-keys": "^1.0.0" - } - }, - "source-map": { - "version": "0.6.1", - "dev": true - }, - "source-map-js": { - "version": "1.0.2" - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "spawn-command": { - "version": "0.0.2-1", - "dev": true - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true - }, - "stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "requires": { - "escape-string-regexp": "^2.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true - } - } - }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "requires": { - "safe-buffer": "~5.2.0" - } - }, - "string-length": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", - "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", - "dev": true, - "requires": { - "char-regex": "^1.0.2", - "strip-ansi": "^6.0.0" - } - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-bom": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", - "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", - "dev": true - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "dev": true - }, - "strip-outer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-2.0.0.tgz", - "integrity": "sha512-A21Xsm1XzUkK0qK1ZrytDUvqsQWict2Cykhvi0fBQntGG5JSprESasEyV1EZ/4CiR5WB5KjzLTrP/bO37B0wPg==", - "dev": true - }, - "strtok3": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.0.0.tgz", - "integrity": "sha512-pQ+V+nYQdC5H3Q7qBZAz/MO6lwGhoC2gOAjuouGf/VO0m7vQRh8QNMl2Uf6SwAtzZ9bOw3UIeBukEGNJl5dtXQ==", - "dev": true, - "requires": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^5.0.0" - } - }, - "stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - } - }, - "sucrase": { - "version": "3.32.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", - "integrity": "sha512-ydQOU34rpSyj2TGyz4D2p8rbktIOZ8QY9s+DGLvFU1i5pWJE8vkpruCjGCMHsdXwnD7JDcS+noSwM/a7zyNFDQ==", - "requires": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "dependencies": { - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==" - } - } - }, - "supports-color": { - "version": "7.2.0", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0" - }, - "svgo": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.0.2.tgz", - "integrity": "sha512-Z706C1U2pb1+JGP48fbazf3KxHrWOsLme6Rv7imFBn5EnuanDW1GPaA/P1/dvObE670JDePC3mnj0k0B7P0jjQ==", - "dev": true, - "requires": { - "@trysound/sax": "0.2.0", - "commander": "^7.2.0", - "css-select": "^5.1.0", - "css-tree": "^2.2.1", - "csso": "^5.0.5", - "picocolors": "^1.0.0" - } - }, - "test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "requires": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - } - }, - "text-table": { - "version": "0.2.0", - "dev": true - }, - "thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "tmpl": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", - "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true - }, - "token-types": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", - "integrity": "sha512-Y2fmSnZjQdDb9W4w4r1tswlMHylzWIeOKpx0aZH9BgGtACHhrk3OkT52AzwcuqTRBZtvvnTjDBh8eynMulu8Vg==", - "dev": true, - "requires": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" - } - }, - "tree-kill": { - "version": "1.2.2", - "dev": true - }, - "trim-repeated": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-2.0.0.tgz", - "integrity": "sha512-QUHBFTJGdOwmp0tbOG505xAgOp/YliZP/6UgafFXYZ26WT1bvQmSMJUvkeVSASuJJHbqsFbynTvkd5W8RBTipg==", - "dev": true, - "requires": { - "escape-string-regexp": "^5.0.0" - }, - "dependencies": { - "escape-string-regexp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", - "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", - "dev": true - } - } - }, - "ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" - }, - "tslib": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz", - "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==", - "dev": true - }, - "turbo": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo/-/turbo-1.9.3.tgz", - "integrity": "sha512-ID7mxmaLUPKG/hVkp+h0VuucB1U99RPCJD9cEuSEOdIPoSIuomcIClEJtKamUsdPLhLCud+BvapBNnhgh58Nzw==", - "dev": true, - "requires": { - "turbo-darwin-64": "1.9.3", - "turbo-darwin-arm64": "1.9.3", - "turbo-linux-64": "1.9.3", - "turbo-linux-arm64": "1.9.3", - "turbo-windows-64": "1.9.3", - "turbo-windows-arm64": "1.9.3" - } - }, - "turbo-darwin-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-64/-/turbo-darwin-64-1.9.3.tgz", - "integrity": "sha512-0dFc2cWXl82kRE4Z+QqPHhbEFEpUZho1msHXHWbz5+PqLxn8FY0lEVOHkq5tgKNNEd5KnGyj33gC/bHhpZOk5g==", - "dev": true, - "optional": true - }, - "turbo-darwin-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-darwin-arm64/-/turbo-darwin-arm64-1.9.3.tgz", - "integrity": "sha512-1cYbjqLBA2zYE1nbf/qVnEkrHa4PkJJbLo7hnuMuGM0bPzh4+AnTNe98gELhqI1mkTWBu/XAEeF5u6dgz0jLNA==", - "dev": true, - "optional": true - }, - "turbo-linux-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-64/-/turbo-linux-64-1.9.3.tgz", - "integrity": "sha512-UuBPFefawEwpuxh5pM9Jqq3q4C8M0vYxVYlB3qea/nHQ80pxYq7ZcaLGEpb10SGnr3oMUUs1zZvkXWDNKCJb8Q==", - "dev": true, - "optional": true - }, - "turbo-linux-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-linux-arm64/-/turbo-linux-arm64-1.9.3.tgz", - "integrity": "sha512-vUrNGa3hyDtRh9W0MkO+l1dzP8Co2gKnOVmlJQW0hdpOlWlIh22nHNGGlICg+xFa2f9j4PbQlWTsc22c019s8Q==", - "dev": true, - "optional": true - }, - "turbo-windows-64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-64/-/turbo-windows-64-1.9.3.tgz", - "integrity": "sha512-0BZ7YaHs6r+K4ksqWus1GKK3W45DuDqlmfjm/yuUbTEVc8szmMCs12vugU2Zi5GdrdJSYfoKfEJ/PeegSLIQGQ==", - "dev": true, - "optional": true - }, - "turbo-windows-arm64": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/turbo-windows-arm64/-/turbo-windows-arm64-1.9.3.tgz", - "integrity": "sha512-QJUYLSsxdXOsR1TquiOmLdAgtYcQ/RuSRpScGvnZb1hY0oLc7JWU0llkYB81wVtWs469y8H9O0cxbKwCZGR4RQ==", - "dev": true, - "optional": true - }, - "type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "dev": true - }, - "update-browserslist-db": { - "version": "1.0.10", - "dev": true, - "requires": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - } - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2" - }, - "v8-to-istanbul": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", - "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "^0.3.12", - "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0" - }, - "dependencies": { - "convert-source-map": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", - "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", - "dev": true - } - } - }, - "walker": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", - "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", - "dev": true, - "requires": { - "makeerror": "1.0.12" - } - }, - "which": { - "version": "2.0.2", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "word-wrap": { - "version": "1.2.3", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "wrappy": { - "version": "1.0.2" - }, - "write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", - "dev": true, - "requires": { - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "dev": true - }, - "yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "requires": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - } - }, - "yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true - }, - "yocto-queue": { - "version": "0.1.0", - "dev": true - } - } -} diff --git a/package.json b/package.json index d74c2dcae..5a90f70a5 100644 --- a/package.json +++ b/package.json @@ -16,12 +16,9 @@ "integrations/*", "oxide/crates/node" ], - "tailwindcss": { - "engine": "oxide" - }, "scripts": { "dev": "concurrently -n tailwind,oxide-node -c green,yellow 'npm run dev:js' 'npm run dev:rust'", - "build": "npm run build:rust && npm run build:js && npm run build:peers", + "build": "npm run build:rust && npm run build:js", "test": "jest", "test:integrations": "npm run test -w ./integrations", "style": "eslint .", @@ -29,8 +26,7 @@ "dev:rust": "npm run --prefix ./oxide dev:node", "dev:js": "npm run build:js -- --watch", "build:rust": "npm run --prefix ./oxide build:node", - "build:js": "npm run generate:plugin-list && swc src --out-dir lib --copy-files --delete-dir-on-start --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"true\"'", - "build:peers": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", + "build:js": "npm run generate:plugin-list && swc src --out-dir lib --copy-files --delete-dir-on-start", "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", "generate:types": "node -r @swc/register scripts/generate-types.js" }, @@ -38,7 +34,6 @@ "src/*", "cli/*", "lib/*", - "peers/*", "scripts/*.js", "stubs/*", "nesting/*", @@ -54,8 +49,6 @@ "@swc/register": "^0.1.10", "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", - "cssnano": "^6.0.1", - "esbuild": "^0.17.18", "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", diff --git a/package.stable.json b/package.stable.json deleted file mode 100644 index 0e83f619f..000000000 --- a/package.stable.json +++ /dev/null @@ -1,126 +0,0 @@ -{ - "name": "tailwindcss", - "version": "3.3.2", - "description": "A utility-first CSS framework for rapidly building custom user interfaces.", - "license": "MIT", - "main": "lib/index.js", - "types": "types/index.d.ts", - "repository": "https://github.com/tailwindlabs/tailwindcss.git", - "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", - "homepage": "https://tailwindcss.com", - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "tailwindcss": { - "engine": "stable" - }, - "scripts": { - "prebuild": "npm run generate && rimraf lib", - "build": "swc src --out-dir lib --copy-files --config jsc.transform.optimizer.globals.vars.__OXIDE__='\"false\"'", - "postbuild": "esbuild lib/cli-peer-dependencies.js --bundle --platform=node --outfile=peers/index.js --define:process.env.CSS_TRANSFORMER_WASM=false", - "rebuild-fixtures": "npm run build && node -r @swc/register scripts/rebuildFixtures.js", - "style": "eslint .", - "pretest": "npm run generate", - "test": "jest", - "test:integrations": "npm run test --prefix ./integrations", - "install:integrations": "node scripts/install-integrations.js", - "generate:plugin-list": "node -r @swc/register scripts/create-plugin-list.js", - "generate:types": "node -r @swc/register scripts/generate-types.js", - "generate": "npm run generate:plugin-list && npm run generate:types", - "release-channel": "node ./scripts/release-channel.js", - "release-notes": "node ./scripts/release-notes.js", - "prepublishOnly": "npm install --force && npm run build" - }, - "files": [ - "src/*", - "cli/*", - "lib/*", - "peers/*", - "scripts/*.js", - "stubs/*", - "nesting/*", - "types/**/*", - "*.d.ts", - "*.js", - "base.css", - "components.css", - "screens.css", - "tailwind.css", - "utilities.css", - "variants.css" - ], - "devDependencies": { - "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.55", - "@swc/jest": "^0.2.26", - "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", - "browserslist": "^4.21.5", - "concurrently": "^8.0.1", - "cssnano": "^6.0.0", - "esbuild": "^0.17.18", - "eslint": "^8.39.0", - "eslint-config-prettier": "^8.8.0", - "eslint-plugin-prettier": "^4.2.1", - "jest": "^29.5.0", - "jest-diff": "^29.5.0", - "lightningcss": "1.18.0", - "prettier": "^2.8.8", - "rimraf": "^5.0.0", - "source-map-js": "^1.0.2", - "turbo": "^1.9.3" - }, - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "browserslist": [ - "> 1%", - "not edge <= 18", - "not ie 11", - "not op_mini all" - ], - "jest": { - "testTimeout": 30000, - "setupFilesAfterEnv": [ - "/jest/customMatchers.js" - ], - "testPathIgnorePatterns": [ - "/node_modules/", - "/integrations/", - "/standalone-cli/", - "\\.test\\.skip\\.js$" - ], - "transformIgnorePatterns": [ - "node_modules/(?!lightningcss)" - ], - "transform": { - "\\.js$": "@swc/jest", - "\\.ts$": "@swc/jest" - } - }, - "engines": { - "node": ">=14.0.0" - } -} diff --git a/scripts/swap-engines.js b/scripts/swap-engines.js deleted file mode 100644 index ef8308aeb..000000000 --- a/scripts/swap-engines.js +++ /dev/null @@ -1,40 +0,0 @@ -let fs = require('fs') -let path = require('path') - -let engines = { - stable: { - files: [ - path.resolve(__dirname, '..', 'package.stable.json'), - path.resolve(__dirname, '..', 'package-lock.stable.json'), - ], - }, - oxide: { - files: [ - path.resolve(__dirname, '..', 'package.oxide.json'), - path.resolve(__dirname, '..', 'package-lock.oxide.json'), - ], - }, -} - -// Find out what the current engine is that we are using: -let [otherEngine, info] = Object.entries(engines).find(([, info]) => - info.files.every((file) => fs.existsSync(file)) -) -let currentEngine = otherEngine === 'oxide' ? 'stable' : 'oxide' - -console.log(`Current engine: \`${currentEngine}\`, swapping to \`${otherEngine}\``) - -// Swap the engines -for (let file of info.files) { - fs.renameSync( - file.replace(`.${otherEngine}`, ''), - file.replace(`.${otherEngine}`, `.${currentEngine}`) - ) -} -for (let file of engines[otherEngine].files) { - fs.renameSync(file, file.replace(`.${otherEngine}`, '')) -} - -console.log( - 'Engines have been swapped. Make sure to run `npm install` to update your dependencies.' -) diff --git a/src/cli-peer-dependencies.js b/src/cli-peer-dependencies.js deleted file mode 100644 index 6b9f986aa..000000000 --- a/src/cli-peer-dependencies.js +++ /dev/null @@ -1,15 +0,0 @@ -export function lazyPostcss() { - return require('postcss') -} - -export function lazyPostcssImport() { - return require('postcss-import') -} - -export function lazyAutoprefixer() { - return require('autoprefixer') -} - -export function lazyCssnano() { - return require('cssnano') -} diff --git a/src/cli.js b/src/cli.js index 4b73accbb..9a5aff27b 100644 --- a/src/cli.js +++ b/src/cli.js @@ -1,7 +1,3 @@ #!/usr/bin/env node -if (__OXIDE__) { - module.exports = require('./oxide/cli') -} else { - module.exports = require('./cli/index') -} +module.exports = require('./cli/index') diff --git a/src/cli/build/deps.js b/src/cli/build/deps.js deleted file mode 100644 index 9435b929a..000000000 --- a/src/cli/build/deps.js +++ /dev/null @@ -1,56 +0,0 @@ -// @ts-check - -import { - // @ts-ignore - lazyPostcss, - - // @ts-ignore - lazyPostcssImport, - - // @ts-ignore - lazyCssnano, - - // @ts-ignore - lazyAutoprefixer, -} from '../../../peers/index.js' - -/** - * @returns {import('postcss')} - */ -export function loadPostcss() { - // Try to load a local `postcss` version first - try { - return require('postcss') - } catch {} - - return lazyPostcss() -} - -export function loadPostcssImport() { - // Try to load a local `postcss-import` version first - try { - return require('postcss-import') - } catch {} - - return lazyPostcssImport() -} - -export function loadCssNano() { - let options = { preset: ['default', { cssDeclarationSorter: false }] } - - // Try to load a local `cssnano` version first - try { - return require('cssnano') - } catch {} - - return lazyCssnano()(options) -} - -export function loadAutoprefixer() { - // Try to load a local `autoprefixer` version first - try { - return require('autoprefixer') - } catch {} - - return lazyAutoprefixer() -} diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index a5045593d..ee30eb442 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -1,14 +1,17 @@ // @ts-check +import pkg from '../../../package.json' import path from 'path' import fs from 'fs' +import postcss from 'postcss' import postcssrc from 'postcss-load-config' +import browserslist from 'browserslist' +import lightning from 'lightningcss' import { lilconfig } from 'lilconfig' import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API import loadOptions from 'postcss-load-config/src/options' // Little bit scary, looking at private/internal API import tailwind from '../../processTailwindFeatures' -import { loadAutoprefixer, loadCssNano, loadPostcss, loadPostcssImport } from './deps' import { formatNodes, drainStdin, outputFile } from './utils' import { env } from '../../lib/sharedState' import resolveConfig from '../../../resolveConfig.js' @@ -20,6 +23,41 @@ import log from '../../util/log' import { loadConfig } from '../../lib/load-config' import getModuleDependencies from '../../lib/getModuleDependencies' import { validateConfig } from '../../util/validateConfig' +import { handleImportAtRules } from '../../lib/handleImportAtRules' +import { flagEnabled } from '../../featureFlags' + +async function lightningcss(shouldMinify, result, options = {}) { + // TODO: handle --no-autoprefixer option if possible + try { + let transformed = lightning.transform({ + filename: result.opts.from || 'input.css', + code: Buffer.from(result.css, 'utf-8'), + minify: shouldMinify, + sourceMap: result.map === undefined ? options.map : !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: lightning.browserslistToTargets(browserslist(pkg.browserslist)), + drafts: { + nesting: true, + }, + }) + + return Object.assign(result, { + css: transformed.code.toString('utf8'), + map: result.map + ? Object.assign(result.map, { + toString() { + return transformed.map.toString() + }, + }) + : result.map, + }) + } catch (err) { + console.error('Unable to use Lightning CSS. Using raw version instead.') + console.error(err) + + return result + } +} /** * @@ -76,39 +114,6 @@ async function loadPostCssPlugins(customPostCssPath) { return [beforePlugins, afterPlugins, config.options] } -function loadBuiltinPostcssPlugins() { - let postcss = loadPostcss() - let IMPORT_COMMENT = '__TAILWIND_RESTORE_IMPORT__: ' - return [ - [ - (root) => { - root.walkAtRules('import', (rule) => { - if (rule.params.slice(1).startsWith('tailwindcss/')) { - rule.after(postcss.comment({ text: IMPORT_COMMENT + rule.params })) - rule.remove() - } - }) - }, - loadPostcssImport(), - (root) => { - root.walkComments((rule) => { - if (rule.text.startsWith(IMPORT_COMMENT)) { - rule.after( - postcss.atRule({ - name: 'import', - params: rule.text.replace(IMPORT_COMMENT, ''), - }) - ) - rule.remove() - } - }) - }, - ], - [], - {}, - ] -} - let state = { /** @type {any} */ context: null, @@ -119,7 +124,7 @@ let state = { /** @type {{content: string, extension: string}[]} */ changedContent: [], - /** @type {ReturnType | null} */ + /** @type {{config: import('../../../types').Config, dependencies: Set, dispose: Function } | null} */ configBag: null, contextDependencies: new Set(), @@ -161,14 +166,7 @@ let state = { }, } - // @ts-ignore - if (__OXIDE__) { - this.configBag.config = validateConfig(resolveConfig(this.configBag.config)) - } else { - this.configBag.config = validateConfig( - resolveConfig(this.configBag.config, { content: { files: [] } }) - ) - } + this.configBag.config = validateConfig(resolveConfig(this.configBag.config)) // Override content files if `--content` has been passed explicitly if (content?.length > 0) { @@ -192,7 +190,7 @@ let state = { let files = fastGlob.sync(this.contentPatterns.all) for (let file of files) { - if (__OXIDE__) { + if (flagEnabled(this.config, 'oxideParser')) { content.push({ file, extension: path.extname(file).slice(1), @@ -258,8 +256,6 @@ let state = { } export async function createProcessor(args, cliConfigPath) { - let postcss = loadPostcss() - let input = args['--input'] let output = args['--output'] let includePostCss = args['--postcss'] @@ -267,7 +263,9 @@ export async function createProcessor(args, cliConfigPath) { let [beforePlugins, afterPlugins, postcssOptions] = includePostCss ? await loadPostCssPlugins(customPostCssPath) - : loadBuiltinPostcssPlugins() + : [[], [], {}] + + beforePlugins.unshift(...handleImportAtRules()) if (args['--purge']) { log.warn('purge-flag-deprecated', [ @@ -313,8 +311,6 @@ export async function createProcessor(args, cliConfigPath) { tailwindPlugin, !args['--minify'] && formatNodes, ...afterPlugins, - !args['--no-autoprefixer'] && loadAutoprefixer(), - args['--minify'] && loadCssNano(), ].filter(Boolean) /** @type {import('postcss').Processor} */ @@ -338,9 +334,15 @@ export async function createProcessor(args, cliConfigPath) { async function build() { let start = process.hrtime.bigint() + let options = { + ...postcssOptions, + from: input, + to: output, + } return readInput() - .then((css) => processor.process(css, { ...postcssOptions, from: input, to: output })) + .then((css) => processor.process(css, options)) + .then((result) => lightningcss(!!args['--minify'], result, options)) .then((result) => { if (!state.watcher) { return result diff --git a/src/cli/init/index.js b/src/cli/init/index.js index b344b5b2e..6bd7e41e2 100644 --- a/src/cli/init/index.js +++ b/src/cli/init/index.js @@ -38,11 +38,6 @@ export function init(args) { 'utf8' ) - // Drop `content` in the oxide engine to promote auto content - if (__OXIDE__) { - stubContentsFile = stubContentsFile.replace(/ *content: \[\],\n/, '') - } - // Change colors import stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors') diff --git a/src/corePlugins.js b/src/corePlugins.js index e4d2ff279..fc373a77f 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1255,13 +1255,13 @@ export let corePlugins = { ], ]), - space: ({ matchUtilities, addUtilities, theme }) => { + space: ({ matchUtilities, addUtilities, theme, config }) => { matchUtilities( { 'space-x': (value) => { value = value === '0' ? '0px' : value - if (__OXIDE__) { + if (flagEnabled(config(), 'logicalSiblingUtilities')) { return { '& > :not([hidden]) ~ :not([hidden])': { '--tw-space-x-reverse': '0', @@ -1300,13 +1300,13 @@ export let corePlugins = { }) }, - divideWidth: ({ matchUtilities, addUtilities, theme }) => { + divideWidth: ({ matchUtilities, addUtilities, theme, config }) => { matchUtilities( { 'divide-x': (value) => { value = value === '0' ? '0px' : value - if (__OXIDE__) { + if (flagEnabled(config(), 'logicalSiblingUtilities')) { return { '& > :not([hidden]) ~ :not([hidden])': { '@defaults border-width': {}, diff --git a/src/featureFlags.js b/src/featureFlags.js index dc9f2d7c4..b4eca6665 100644 --- a/src/featureFlags.js +++ b/src/featureFlags.js @@ -3,13 +3,10 @@ import log from './util/log' let defaults = { optimizeUniversalDefaults: false, - generalizedModifiers: true, - get disableColorOpacityUtilitiesByDefault() { - return __OXIDE__ - }, - get relativeContentPathsByDefault() { - return __OXIDE__ - }, + disableColorOpacityUtilitiesByDefault: false, + relativeContentPathsByDefault: false, + oxideParser: false, + logicalSiblingUtilities: false, } let featureFlags = { @@ -18,10 +15,11 @@ let featureFlags = { 'respectDefaultRingColorOpacity', 'disableColorOpacityUtilitiesByDefault', 'relativeContentPathsByDefault', + 'logicalSiblingUtilities', ], experimental: [ 'optimizeUniversalDefaults', - 'generalizedModifiers', + 'oxideParser', // 'variantGrouping', ], } diff --git a/src/lib/content.js b/src/lib/content.js index 7b58e9d67..9979d251d 100644 --- a/src/lib/content.js +++ b/src/lib/content.js @@ -7,6 +7,7 @@ import fastGlob from 'fast-glob' import normalizePath from 'normalize-path' import { parseGlob } from '../util/parseGlob' import { env } from './sharedState' +import { resolveContentPaths } from '@tailwindcss/oxide' /** @typedef {import('../../types/config.js').RawFile} RawFile */ /** @typedef {import('../../types/config.js').FilePath} FilePath */ @@ -17,17 +18,24 @@ import { env } from './sharedState' * @returns {ContentPath[]} */ function resolveContentFiles(tailwindConfig, { skip = [] } = {}) { - if (tailwindConfig.content.files === 'auto' && __OXIDE__) { - env.DEBUG && console.time('Calculating resolve content paths') - tailwindConfig.content.files = require('@tailwindcss/oxide').resolveContentPaths({ - base: process.cwd(), - }) - if (skip.length > 0) { - tailwindConfig.content.files = tailwindConfig.content.files.filter( - (filePath) => !skip.includes(filePath) - ) + if ( + Array.isArray(tailwindConfig.content.files) && + tailwindConfig.content.files.includes('auto') + ) { + let idx = tailwindConfig.content.files.indexOf('auto') + if (idx !== -1) { + env.DEBUG && console.time('Calculating resolve content paths') + let resolved = resolveContentPaths({ base: process.cwd() }) + env.DEBUG && console.timeEnd('Calculating resolve content paths') + + tailwindConfig.content.files.splice(idx, 1, ...resolved) } - env.DEBUG && console.timeEnd('Calculating resolve content paths') + } + + if (skip.length > 0) { + tailwindConfig.content.files = tailwindConfig.content.files.filter( + (filePath) => !skip.includes(filePath) + ) } return tailwindConfig.content.files @@ -191,12 +199,9 @@ function resolvePathSymlinks(contentPath) { * @returns {[{ content: string, extension: string }[], Map]} */ export function resolvedChangedContent(context, candidateFiles, fileModifiedMap) { - let changedContent = - context.tailwindConfig.content.files === 'auto' && __OXIDE__ - ? [] - : context.tailwindConfig.content.files - .filter((item) => typeof item.raw === 'string') - .map(({ raw, extension = 'html' }) => ({ content: raw, extension })) + let changedContent = context.tailwindConfig.content.files + .filter((item) => typeof item.raw === 'string') + .map(({ raw, extension = 'html' }) => ({ content: raw, extension })) let [changedFiles, mTimesToCommit] = resolveChangedFiles(candidateFiles, fileModifiedMap) diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index bf7d8f17f..c3fbc8cc2 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -1,10 +1,12 @@ import fs from 'fs' import LRU from '@alloc/quick-lru' +import { parseCandidateStringsFromFiles } from '@tailwindcss/oxide' import * as sharedState from './sharedState' import { generateRules } from './generateRules' import log from '../util/log' import cloneNodes from '../util/cloneNodes' import { defaultExtractor } from './defaultExtractor' +import { flagEnabled } from '../featureFlags' let env = sharedState.env @@ -130,9 +132,9 @@ export default function expandTailwindAtRules(context) { env.DEBUG && console.time('Reading changed files') - if (__OXIDE__) { + if (flagEnabled(context.tailwindConfig, 'oxideParser')) { // TODO: Pass through or implement `extractor` - for (let candidate of require('@tailwindcss/oxide').parseCandidateStringsFromFiles( + for (let candidate of parseCandidateStringsFromFiles( context.changedContent // Object.assign({}, builtInTransformers, context.tailwindConfig.content.transform) )) { @@ -162,7 +164,7 @@ export default function expandTailwindAtRules(context) { env.DEBUG && console.time('Generate rules') env.DEBUG && console.time('Sorting candidates') - let sortedCandidates = __OXIDE__ + let sortedCandidates = flagEnabled(context.tailwindConfig, 'oxideParser') ? candidates : new Set( [...candidates].sort((a, z) => { diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index cbd671075..3aec15951 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -175,10 +175,6 @@ function applyVariant(variant, matches, context) { if (modifiers.length && !context.variantMap.has(variant)) { variant = baseVariant args.modifier = modifiers[0] - - if (!flagEnabled(context.tailwindConfig, 'generalizedModifiers')) { - return [] - } } } diff --git a/src/lib/handleImportAtRules.js b/src/lib/handleImportAtRules.js index 57587d309..bcb55b5db 100644 --- a/src/lib/handleImportAtRules.js +++ b/src/lib/handleImportAtRules.js @@ -1,8 +1,9 @@ import postcss from 'postcss' +import postcssImport from 'postcss-import' const TAILWIND = Symbol() -export function handleImportAtRules(postcssImport = require('postcss-import')) { +export function handleImportAtRules() { let RESTORE_ATRULE_COMMENT = '__TAILWIND_RESTORE__' let atRulesToRestore = ['tailwind', 'config'] diff --git a/src/lib/normalizeTailwindDirectives.js b/src/lib/normalizeTailwindDirectives.js index 530ff35b3..0366d1662 100644 --- a/src/lib/normalizeTailwindDirectives.js +++ b/src/lib/normalizeTailwindDirectives.js @@ -10,35 +10,6 @@ export default function normalizeTailwindDirectives(root) { applyDirectives.add(atRule) } - if (!__OXIDE__) { - if (atRule.name === 'import') { - if (atRule.params === '"tailwindcss/base"' || atRule.params === "'tailwindcss/base'") { - atRule.name = 'tailwind' - atRule.params = 'base' - } else if ( - atRule.params === '"tailwindcss/components"' || - atRule.params === "'tailwindcss/components'" - ) { - atRule.name = 'tailwind' - atRule.params = 'components' - } else if ( - atRule.params === '"tailwindcss/utilities"' || - atRule.params === "'tailwindcss/utilities'" - ) { - atRule.name = 'tailwind' - atRule.params = 'utilities' - } else if ( - atRule.params === '"tailwindcss/screens"' || - atRule.params === "'tailwindcss/screens'" || - atRule.params === '"tailwindcss/variants"' || - atRule.params === "'tailwindcss/variants'" - ) { - atRule.name = 'tailwind' - atRule.params = 'variants' - } - } - } - if (atRule.name === 'tailwind') { if (atRule.params === 'screens') { atRule.params = 'variants' diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index 0749da68d..017f31170 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -21,7 +21,6 @@ import isSyntacticallyValidPropertyValue from '../util/isSyntacticallyValidPrope import { generateRules, getClassNameFromSelector } from './generateRules' import { hasContentChanged } from './cacheInvalidation.js' import { Offsets } from './offsets.js' -import { flagEnabled } from '../featureFlags.js' import { finalizeSelector, formatVariantSelector } from '../util/formatVariantSelector' const VARIANT_TYPES = { @@ -434,10 +433,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs }, } - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - let ruleSets = [] - .concat(modifiersEnabled ? rule(value, extras) : rule(value)) + .concat(rule(value, extras)) .filter(Boolean) .map((declaration) => ({ [nameClass(identifier, modifier)]: declaration, @@ -514,10 +511,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs }, } - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - let ruleSets = [] - .concat(modifiersEnabled ? rule(value, extras) : rule(value)) + .concat(rule(value, extras)) .filter(Boolean) .map((declaration) => ({ [nameClass(identifier, modifier)]: declaration, @@ -585,18 +580,13 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs let id = options?.id ?? ++variantIdentifier let isSpecial = variant === '@' - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - for (let [key, value] of Object.entries(options?.values ?? {})) { if (key === 'DEFAULT') continue api.addVariant( isSpecial ? `${variant}${key}` : `${variant}-${key}`, ({ args, container }) => { - return variantFn( - value, - modifiersEnabled ? { modifier: args?.modifier, container } : { container } - ) + return variantFn(value, { modifier: args?.modifier, container }) }, { @@ -624,7 +614,7 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs : // Falling back to args if it is a string, otherwise '' for older intellisense // (JetBrains) plugins. args?.value ?? (typeof args === 'string' ? args : ''), - modifiersEnabled ? { modifier: args?.modifier, container } : { container } + { modifier: args?.modifier, container } ) }, { diff --git a/src/lib/setupTrackingContext.js b/src/lib/setupTrackingContext.js index 2b281377d..70e7cb684 100644 --- a/src/lib/setupTrackingContext.js +++ b/src/lib/setupTrackingContext.js @@ -63,9 +63,7 @@ function getTailwindConfig(configOrPath) { } // It's a plain object, not a path - let newConfig = resolveConfig( - configOrPath.config === undefined ? configOrPath : configOrPath.config - ) + let newConfig = resolveConfig(configOrPath?.config ?? configOrPath ?? {}) newConfig = validateConfig(newConfig) diff --git a/src/lib/sharedState.js b/src/lib/sharedState.js index 97bdf09c5..915dd21cb 100644 --- a/src/lib/sharedState.js +++ b/src/lib/sharedState.js @@ -1,16 +1,12 @@ -import pkg from '../../package.json' - export const env = typeof process !== 'undefined' ? { NODE_ENV: process.env.NODE_ENV, DEBUG: resolveDebug(process.env.DEBUG), - ENGINE: pkg.tailwindcss.engine, } : { NODE_ENV: 'production', DEBUG: false, - ENGINE: pkg.tailwindcss.engine, } export const contextMap = new Map() diff --git a/src/oxide/cli.ts b/src/oxide/cli.ts deleted file mode 100644 index 17552ecb1..000000000 --- a/src/oxide/cli.ts +++ /dev/null @@ -1 +0,0 @@ -import './cli/index' diff --git a/src/oxide/cli/build/deps.ts b/src/oxide/cli/build/deps.ts deleted file mode 100644 index 2b4355b17..000000000 --- a/src/oxide/cli/build/deps.ts +++ /dev/null @@ -1,91 +0,0 @@ -import packageJson from '../../../../package.json' -import browserslist from 'browserslist' -import { Result } from 'postcss' - -import { - // @ts-ignore - lazyPostcss, - - // @ts-ignore - lazyPostcssImport, - - // @ts-ignore - lazyCssnano, - - // @ts-ignore -} from '../../../../peers/index' - -export function lazyLightningCss() { - // TODO: Make this lazy/bundled - return require('lightningcss') -} - -let lightningCss - -function loadLightningCss() { - if (lightningCss) { - return lightningCss - } - - // Try to load a local version first - try { - return (lightningCss = require('lightningcss')) - } catch {} - - return (lightningCss = lazyLightningCss()) -} - -export async function lightningcss(shouldMinify: boolean, result: Result) { - let css = loadLightningCss() - - try { - let transformed = css.transform({ - filename: result.opts.from || 'input.css', - code: Buffer.from(result.css, 'utf-8'), - minify: shouldMinify, - sourceMap: !!result.map, - inputSourceMap: result.map ? result.map.toString() : undefined, - targets: css.browserslistToTargets(browserslist(packageJson.browserslist)), - drafts: { - nesting: true, - }, - }) - - return Object.assign(result, { - css: transformed.code.toString('utf8'), - map: result.map - ? Object.assign(result.map, { - toString() { - return transformed.map.toString() - }, - }) - : result.map, - }) - } catch (err) { - console.error('Unable to use Lightning CSS. Using raw version instead.') - console.error(err) - - return result - } -} - -/** - * @returns {import('postcss')} - */ -export function loadPostcss() { - // Try to load a local `postcss` version first - try { - return require('postcss') - } catch {} - - return lazyPostcss() -} - -export function loadPostcssImport() { - // Try to load a local `postcss-import` version first - try { - return require('postcss-import') - } catch {} - - return lazyPostcssImport() -} diff --git a/src/oxide/cli/build/index.ts b/src/oxide/cli/build/index.ts deleted file mode 100644 index ba7c87459..000000000 --- a/src/oxide/cli/build/index.ts +++ /dev/null @@ -1,47 +0,0 @@ -import fs from 'fs' -import path from 'path' -import { resolveDefaultConfigPath } from '../../../util/resolveConfigPath' -import { createProcessor } from './plugin' - -export async function build(args) { - let input = args['--input'] - let shouldWatch = args['--watch'] - - // TODO: Deprecate this in future versions - if (!input && args['_'][1]) { - console.error('[deprecation] Running tailwindcss without -i, please provide an input file.') - input = args['--input'] = args['_'][1] - } - - if (input && input !== '-' && !fs.existsSync((input = path.resolve(input)))) { - console.error(`Specified input file ${args['--input']} does not exist.`) - process.exit(9) - } - - if (args['--config'] && !fs.existsSync((args['--config'] = path.resolve(args['--config'])))) { - console.error(`Specified config file ${args['--config']} does not exist.`) - process.exit(9) - } - - // TODO: Reference the @config path here if exists - let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath() - - let processor = await createProcessor(args, configPath) - - if (shouldWatch) { - // Abort the watcher if stdin is closed to avoid zombie processes - // You can disable this behavior with --watch=always - if (args['--watch'] !== 'always') { - process.stdin.on('end', () => process.exit(0)) - } - - process.stdin.resume() - - await processor.watch() - } else { - await processor.build().catch((e) => { - console.error(e) - process.exit(1) - }) - } -} diff --git a/src/oxide/cli/build/plugin.ts b/src/oxide/cli/build/plugin.ts deleted file mode 100644 index f6193b534..000000000 --- a/src/oxide/cli/build/plugin.ts +++ /dev/null @@ -1,419 +0,0 @@ -import path from 'path' -import fs from 'fs' -import postcssrc from 'postcss-load-config' -import { lilconfig } from 'lilconfig' -import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API -import loadOptions from 'postcss-load-config/src/options' // Little bit scary, looking at private/internal API - -import tailwind from '../../../processTailwindFeatures' -import { loadPostcss, loadPostcssImport, lightningcss } from './deps' -import { formatNodes, drainStdin, outputFile } from './utils' -import { env } from '../../../lib/sharedState' -import resolveConfig from '../../../../resolveConfig' -import { parseCandidateFiles } from '../../../lib/content' -import { createWatcher } from './watching' -import fastGlob from 'fast-glob' -import { findAtConfigPath } from '../../../lib/findAtConfigPath' -import log from '../../../util/log' -import { loadConfig } from '../../../lib/load-config' -import getModuleDependencies from '../../../lib/getModuleDependencies' -import type { Config } from '../../../../types' -import { validateConfig } from '../../../util/validateConfig' -import { handleImportAtRules } from '../../../lib/handleImportAtRules' - -/** - * - * @param {string} [customPostCssPath ] - * @returns - */ -async function loadPostCssPlugins(customPostCssPath) { - let config = customPostCssPath - ? await (async () => { - let file = path.resolve(customPostCssPath) - - // Implementation, see: https://unpkg.com/browse/postcss-load-config@3.1.0/src/index.js - // @ts-ignore - let { config = {} } = await lilconfig('postcss').load(file) - if (typeof config === 'function') { - config = config() - } else { - config = Object.assign({}, config) - } - - if (!config.plugins) { - config.plugins = [] - } - - return { - file, - plugins: loadPlugins(config, file), - options: loadOptions(config, file), - } - })() - : await postcssrc() - - let configPlugins = config.plugins - - let configPluginTailwindIdx = configPlugins.findIndex((plugin) => { - if (typeof plugin === 'function' && plugin.name === 'tailwindcss') { - return true - } - - if (typeof plugin === 'object' && plugin !== null && plugin.postcssPlugin === 'tailwindcss') { - return true - } - - return false - }) - - let beforePlugins = - configPluginTailwindIdx === -1 ? [] : configPlugins.slice(0, configPluginTailwindIdx) - let afterPlugins = - configPluginTailwindIdx === -1 - ? configPlugins - : configPlugins.slice(configPluginTailwindIdx + 1) - - return [beforePlugins, afterPlugins, config.options] -} - -let state = { - /** @type {any} */ - context: null, - - /** @type {ReturnType | null} */ - watcher: null, - - /** @type {{content: string, extension: string}[]} */ - changedContent: [], - - /** @type {{config: Config, dependencies: Set, dispose: Function } | null} */ - configBag: null, - - contextDependencies: new Set(), - - /** @type {import('../../lib/content.js').ContentPath[]} */ - contentPaths: [], - - refreshContentPaths() { - this.contentPaths = parseCandidateFiles(this.context, this.context?.tailwindConfig) - }, - - get config() { - return this.context.tailwindConfig - }, - - get contentPatterns() { - return { - all: this.contentPaths.map((contentPath) => contentPath.pattern), - dynamic: this.contentPaths - .filter((contentPath) => contentPath.glob !== undefined) - .map((contentPath) => contentPath.pattern), - } - }, - - loadConfig(configPath, content) { - if (this.watcher && configPath) { - this.refreshConfigDependencies() - } - - let config = loadConfig(configPath) - let dependencies = getModuleDependencies(configPath) - this.configBag = { - config, - dependencies, - dispose() { - for (let file of dependencies) { - delete require.cache[require.resolve(file)] - } - }, - } - - // @ts-ignore - if (__OXIDE__) { - this.configBag.config = validateConfig(resolveConfig(this.configBag.config)) - } else { - this.configBag.config = validateConfig( - resolveConfig(this.configBag.config, { content: { files: [] } }) - ) - } - - // Override content files if `--content` has been passed explicitly - if (content?.length > 0) { - this.configBag.config.content.files = content - } - - return this.configBag.config - }, - - refreshConfigDependencies(configPath) { - env.DEBUG && console.time('Module dependencies') - this.configBag?.dispose() - env.DEBUG && console.timeEnd('Module dependencies') - }, - - readContentPaths() { - let content = [] - - // Resolve globs from the content config - // TODO: When we make the postcss plugin async-capable this can become async - let files = fastGlob.sync(this.contentPatterns.all) - - for (let file of files) { - if (__OXIDE__) { - content.push({ - file, - extension: path.extname(file).slice(1), - }) - } else { - content.push({ - content: fs.readFileSync(path.resolve(file), 'utf8'), - extension: path.extname(file).slice(1), - }) - } - } - - // Resolve raw content in the tailwind config - let rawContent = this.config.content.files.filter((file) => { - return file !== null && typeof file === 'object' - }) - - for (let { raw: htmlContent, extension = 'html' } of rawContent) { - content.push({ content: htmlContent, extension }) - } - - return content - }, - - getContext({ createContext, cliConfigPath, root, result, content }) { - if (this.context) { - this.context.changedContent = this.changedContent.splice(0) - - return this.context - } - - env.DEBUG && console.time('Searching for config') - let configPath = findAtConfigPath(root, result) ?? cliConfigPath - env.DEBUG && console.timeEnd('Searching for config') - - env.DEBUG && console.time('Loading config') - let config = this.loadConfig(configPath, content) - env.DEBUG && console.timeEnd('Loading config') - - env.DEBUG && console.time('Creating context') - this.context = createContext(config, []) - Object.assign(this.context, { - userConfigPath: configPath, - }) - env.DEBUG && console.timeEnd('Creating context') - - env.DEBUG && console.time('Resolving content paths') - this.refreshContentPaths() - env.DEBUG && console.timeEnd('Resolving content paths') - - if (this.watcher) { - env.DEBUG && console.time('Watch new files') - this.watcher.refreshWatchedFiles() - env.DEBUG && console.timeEnd('Watch new files') - } - - for (let file of this.readContentPaths()) { - this.context.changedContent.push(file) - } - - return this.context - }, -} - -export async function createProcessor(args, cliConfigPath) { - let postcss = loadPostcss() - - let input = args['--input'] - let output = args['--output'] - let includePostCss = args['--postcss'] - let customPostCssPath = typeof args['--postcss'] === 'string' ? args['--postcss'] : undefined - - let [beforePlugins, afterPlugins, postcssOptions] = includePostCss - ? await loadPostCssPlugins(customPostCssPath) - : [[], [], {}] - - beforePlugins.unshift(...handleImportAtRules(loadPostcssImport())) - - if (args['--purge']) { - log.warn('purge-flag-deprecated', [ - 'The `--purge` flag has been deprecated.', - 'Please use `--content` instead.', - ]) - - if (!args['--content']) { - args['--content'] = args['--purge'] - } - } - - let content = args['--content']?.split(/(? { - return { - postcssPlugin: 'tailwindcss', - Once(root, { result }) { - env.DEBUG && console.time('Compiling CSS') - tailwind(({ createContext }) => { - console.error() - console.error('Rebuilding...') - - return () => { - return state.getContext({ - createContext, - cliConfigPath, - root, - result, - content, - }) - } - })(root, result) - env.DEBUG && console.timeEnd('Compiling CSS') - }, - } - } - - tailwindPlugin.postcss = true - - let plugins = [ - ...beforePlugins, - tailwindPlugin, - !args['--minify'] && formatNodes, - ...afterPlugins, - ].filter(Boolean) - - /** @type {import('postcss').Processor} */ - // @ts-ignore - let processor = postcss(plugins) - - async function readInput() { - // Piping in data, let's drain the stdin - if (input === '-') { - return drainStdin() - } - - // Input file has been provided - if (input) { - return fs.promises.readFile(path.resolve(input), 'utf8') - } - - // No input file provided, fallback to default atrules - return '@tailwind base; @tailwind components; @tailwind utilities' - } - - async function build() { - let start = process.hrtime.bigint() - - return readInput() - .then((css) => processor.process(css, { ...postcssOptions, from: input, to: output })) - .then((result) => lightningcss(!!args['--minify'], result)) - .then((result) => { - if (!state.watcher) { - return result - } - - env.DEBUG && console.time('Recording PostCSS dependencies') - for (let message of result.messages) { - if (message.type === 'dependency') { - state.contextDependencies.add(message.file) - } - } - env.DEBUG && console.timeEnd('Recording PostCSS dependencies') - - // TODO: This needs to be in a different spot - env.DEBUG && console.time('Watch new files') - state.watcher.refreshWatchedFiles() - env.DEBUG && console.timeEnd('Watch new files') - - return result - }) - .then((result) => { - if (!output) { - process.stdout.write(result.css) - return - } - - return Promise.all([ - outputFile(result.opts.to, result.css), - result.map && outputFile(result.opts.to + '.map', result.map.toString()), - ]) - }) - .then(() => { - let end = process.hrtime.bigint() - console.error() - console.error('Done in', (end - start) / BigInt(1e6) + 'ms.') - }) - .then( - () => {}, - (err) => { - // TODO: If an initial build fails we can't easily pick up any PostCSS dependencies - // that were collected before the error occurred - // The result is not stored on the error so we have to store it externally - // and pull the messages off of it here somehow - - // This results in a less than ideal DX because the watcher will not pick up - // changes to imported CSS if one of them caused an error during the initial build - // If you fix it and then save the main CSS file so there's no error - // The watcher will start watching the imported CSS files and will be - // resilient to future errors. - - if (state.watcher) { - console.error(err) - } else { - return Promise.reject(err) - } - } - ) - } - - /** - * @param {{file: string, content(): Promise, extension: string}[]} changes - */ - async function parseChanges(changes) { - return Promise.all( - changes.map(async (change) => ({ - content: await change.content(), - extension: change.extension, - })) - ) - } - - if (input !== undefined && input !== '-') { - state.contextDependencies.add(path.resolve(input)) - } - - return { - build, - watch: async () => { - state.watcher = createWatcher(args, { - state, - - /** - * @param {{file: string, content(): Promise, extension: string}[]} changes - */ - async rebuild(changes) { - let needsNewContext = changes.some((change) => { - return ( - state.configBag?.dependencies.has(change.file) || - state.contextDependencies.has(change.file) - ) - }) - - if (needsNewContext) { - state.context = null - } else { - for (let change of await parseChanges(changes)) { - state.changedContent.push(change) - } - } - - return build() - }, - }) - - await build() - }, - } -} diff --git a/src/oxide/cli/build/utils.ts b/src/oxide/cli/build/utils.ts deleted file mode 100644 index 001857a91..000000000 --- a/src/oxide/cli/build/utils.ts +++ /dev/null @@ -1,74 +0,0 @@ -import fs from 'fs' -import path from 'path' - -export function indentRecursive(node, indent = 0) { - node.each && - node.each((child, i) => { - if (!child.raws.before || !child.raws.before.trim() || child.raws.before.includes('\n')) { - child.raws.before = `\n${node.type !== 'rule' && i > 0 ? '\n' : ''}${' '.repeat(indent)}` - } - child.raws.after = `\n${' '.repeat(indent)}` - indentRecursive(child, indent + 1) - }) -} - -export function formatNodes(root) { - indentRecursive(root) - if (root.first) { - root.first.raws.before = '' - } -} - -/** - * When rapidly saving files atomically a couple of situations can happen: - * - The file is missing since the external program has deleted it by the time we've gotten around to reading it from the earlier save. - * - The file is being written to by the external program by the time we're going to read it and is thus treated as busy because a lock is held. - * - * To work around this we retry reading the file a handful of times with a delay between each attempt - * - * @param {string} path - * @param {number} tries - * @returns {Promise} - * @throws {Error} If the file is still missing or busy after the specified number of tries - */ -export async function readFileWithRetries(path, tries = 5) { - for (let n = 0; n <= tries; n++) { - try { - return await fs.promises.readFile(path, 'utf8') - } catch (err) { - if (n !== tries) { - if (err.code === 'ENOENT' || err.code === 'EBUSY') { - await new Promise((resolve) => setTimeout(resolve, 10)) - - continue - } - } - - throw err - } - } -} - -export function drainStdin() { - return new Promise((resolve, reject) => { - let result = '' - process.stdin.on('data', (chunk) => { - result += chunk - }) - process.stdin.on('end', () => resolve(result)) - process.stdin.on('error', (err) => reject(err)) - }) -} - -export async function outputFile(file, newContents) { - try { - let currentContents = await fs.promises.readFile(file, 'utf8') - if (currentContents === newContents) { - return // Skip writing the file - } - } catch {} - - // Write the file - await fs.promises.mkdir(path.dirname(file), { recursive: true }) - await fs.promises.writeFile(file, newContents, 'utf8') -} diff --git a/src/oxide/cli/build/watching.ts b/src/oxide/cli/build/watching.ts deleted file mode 100644 index 9d5680a16..000000000 --- a/src/oxide/cli/build/watching.ts +++ /dev/null @@ -1,225 +0,0 @@ -import chokidar from 'chokidar' -import fs from 'fs' -import micromatch from 'micromatch' -import normalizePath from 'normalize-path' -import path from 'path' - -import { readFileWithRetries } from './utils' - -/** - * The core idea of this watcher is: - * 1. Whenever a file is added, changed, or renamed we queue a rebuild - * 2. Perform as few rebuilds as possible by batching them together - * 3. Coalesce events that happen in quick succession to avoid unnecessary rebuilds - * 4. Ensure another rebuild happens _if_ changed while a rebuild is in progress - */ - -/** - * - * @param {*} args - * @param {{ state, rebuild(changedFiles: any[]): Promise }} param1 - * @returns {{ - * fswatcher: import('chokidar').FSWatcher, - * refreshWatchedFiles(): void, - * }} - */ -export function createWatcher(args, { state, rebuild }) { - let shouldPoll = args['--poll'] - let shouldCoalesceWriteEvents = shouldPoll || process.platform === 'win32' - - // Polling interval in milliseconds - // Used only when polling or coalescing add/change events on Windows - let pollInterval = 10 - - let watcher = chokidar.watch([], { - // Force checking for atomic writes in all situations - // This causes chokidar to wait up to 100ms for a file to re-added after it's been unlinked - // This only works when watching directories though - atomic: true, - - usePolling: shouldPoll, - interval: shouldPoll ? pollInterval : undefined, - ignoreInitial: true, - awaitWriteFinish: shouldCoalesceWriteEvents - ? { - stabilityThreshold: 50, - pollInterval: pollInterval, - } - : false, - }) - - // A queue of rebuilds, file reads, etc… to run - let chain = Promise.resolve() - - /** - * A list of files that have been changed since the last rebuild - * - * @type {{file: string, content: () => Promise, extension: string}[]} - */ - let changedContent = [] - - /** - * A list of files for which a rebuild has already been queued. - * This is used to prevent duplicate rebuilds when multiple events are fired for the same file. - * The rebuilt file is cleared from this list when it's associated rebuild has _started_ - * This is because if the file is changed during a rebuild it won't trigger a new rebuild which it should - **/ - let pendingRebuilds = new Set() - - let _timer - let _reject - - /** - * Rebuilds the changed files and resolves when the rebuild is - * complete regardless of whether it was successful or not - */ - async function rebuildAndContinue() { - let changes = changedContent.splice(0) - - // There are no changes to rebuild so we can just do nothing - if (changes.length === 0) { - return Promise.resolve() - } - - // Clear all pending rebuilds for the about-to-be-built files - changes.forEach((change) => pendingRebuilds.delete(change.file)) - - // Resolve the promise even when the rebuild fails - return rebuild(changes).then( - () => {}, - () => {} - ) - } - - /** - * - * @param {*} file - * @param {(() => Promise) | null} content - * @param {boolean} skipPendingCheck - * @returns {Promise} - */ - function recordChangedFile(file, content = null, skipPendingCheck = false) { - file = path.resolve(file) - - // Applications like Vim/Neovim fire both rename and change events in succession for atomic writes - // In that case rebuild has already been queued by rename, so can be skipped in change - if (pendingRebuilds.has(file) && !skipPendingCheck) { - return Promise.resolve() - } - - // Mark that a rebuild of this file is going to happen - // It MUST happen synchronously before the rebuild is queued for this to be effective - pendingRebuilds.add(file) - - changedContent.push({ - file, - content: content ?? (() => fs.promises.readFile(file, 'utf8')), - extension: path.extname(file).slice(1), - }) - - if (_timer) { - clearTimeout(_timer) - _reject() - } - - // If a rebuild is already in progress we don't want to start another one until the 10ms timer has expired - chain = chain.then( - () => - new Promise((resolve, reject) => { - _timer = setTimeout(resolve, 10) - _reject = reject - }) - ) - - // Resolves once this file has been rebuilt (or the rebuild for this file has failed) - // This queues as many rebuilds as there are changed files - // But those rebuilds happen after some delay - // And will immediately resolve if there are no changes - chain = chain.then(rebuildAndContinue, rebuildAndContinue) - - return chain - } - - watcher.on('change', (file) => recordChangedFile(file)) - watcher.on('add', (file) => recordChangedFile(file)) - - // Restore watching any files that are "removed" - // This can happen when a file is pseudo-atomically replaced (a copy is created, overwritten, the old one is unlinked, and the new one is renamed) - // TODO: An an optimization we should allow removal when the config changes - watcher.on('unlink', (file) => { - file = normalizePath(file) - - // Only re-add the file if it's not covered by a dynamic pattern - if (!micromatch.some([file], state.contentPatterns.dynamic)) { - watcher.add(file) - } - }) - - // Some applications such as Visual Studio (but not VS Code) - // will only fire a rename event for atomic writes and not a change event - // This is very likely a chokidar bug but it's one we need to work around - // We treat this as a change event and rebuild the CSS - watcher.on('raw', (evt, filePath, meta) => { - if (evt !== 'rename') { - return - } - - let watchedPath = meta.watchedPath - - // Watched path might be the file itself - // Or the directory it is in - filePath = watchedPath.endsWith(filePath) ? watchedPath : path.join(watchedPath, filePath) - - // Skip this event since the files it is for does not match any of the registered content globs - if (!micromatch.some([filePath], state.contentPatterns.all)) { - return - } - - // Skip since we've already queued a rebuild for this file that hasn't happened yet - if (pendingRebuilds.has(filePath)) { - return - } - - // We'll go ahead and add the file to the pending rebuilds list here - // It'll be removed when the rebuild starts unless the read fails - // which will be taken care of as well - pendingRebuilds.add(filePath) - - async function enqueue() { - try { - // We need to read the file as early as possible outside of the chain - // because it may be gone by the time we get to it. doing the read - // immediately increases the chance that the file is still there - let content = await readFileWithRetries(path.resolve(filePath)) - - if (content === undefined) { - return - } - - // This will push the rebuild onto the chain - // We MUST skip the rebuild check here otherwise the rebuild will never happen on Linux - // This is because the order of events and timing is different on Linux - // @ts-ignore: TypeScript isn't picking up that content is a string here - await recordChangedFile(filePath, () => content, true) - } catch { - // If reading the file fails, it's was probably a deleted temporary file - // So we can ignore it and no rebuild is needed - } - } - - enqueue().then(() => { - // If the file read fails we still need to make sure the file isn't stuck in the pending rebuilds list - pendingRebuilds.delete(filePath) - }) - }) - - return { - fswatcher: watcher, - - refreshWatchedFiles() { - watcher.add(Array.from(state.contextDependencies)) - watcher.add(Array.from(state.configBag.dependencies)) - watcher.add(state.contentPatterns.all) - }, - } -} diff --git a/src/oxide/cli/help/index.ts b/src/oxide/cli/help/index.ts deleted file mode 100644 index c36042a65..000000000 --- a/src/oxide/cli/help/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import packageJson from '../../../../package.json' - -export function help({ message, usage, commands, options }) { - let indent = 2 - - // Render header - console.log() - console.log(`${packageJson.name} v${packageJson.version}`) - - // Render message - if (message) { - console.log() - for (let msg of message.split('\n')) { - console.log(msg) - } - } - - // Render usage - if (usage && usage.length > 0) { - console.log() - console.log('Usage:') - for (let example of usage) { - console.log(' '.repeat(indent), example) - } - } - - // Render commands - if (commands && commands.length > 0) { - console.log() - console.log('Commands:') - for (let command of commands) { - console.log(' '.repeat(indent), command) - } - } - - // Render options - if (options) { - let groupedOptions = {} - for (let [key, value] of Object.entries(options)) { - if (typeof value === 'object') { - groupedOptions[key] = { ...value, flags: [key] } - } else { - groupedOptions[value].flags.push(key) - } - } - - console.log() - console.log('Options:') - for (let { flags, description, deprecated } of Object.values(groupedOptions)) { - if (deprecated) continue - - if (flags.length === 1) { - console.log( - ' '.repeat(indent + 4 /* 4 = "-i, ".length */), - flags.slice().reverse().join(', ').padEnd(20, ' '), - description - ) - } else { - console.log( - ' '.repeat(indent), - flags.slice().reverse().join(', ').padEnd(24, ' '), - description - ) - } - } - } - - console.log() -} diff --git a/src/oxide/cli/index.ts b/src/oxide/cli/index.ts deleted file mode 100644 index 96b284db9..000000000 --- a/src/oxide/cli/index.ts +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env node - -import path from 'path' -import arg from 'arg' -import fs from 'fs' - -import { build } from './build' -import { help } from './help' -import { init } from './init' - -// --- - -function oneOf(...options) { - return Object.assign( - (value = true) => { - for (let option of options) { - let parsed = option(value) - if (parsed === value) { - return parsed - } - } - - throw new Error('...') - }, - { manualParsing: true } - ) -} - -let commands = { - init: { - run: init, - args: { - '--esm': { type: Boolean, description: `Initialize configuration file as ESM` }, - '--ts': { type: Boolean, description: `Initialize configuration file as TypeScript` }, - '--full': { - type: Boolean, - description: `Include the default values for all options in the generated configuration file`, - }, - '-f': '--full', - }, - }, - build: { - run: build, - args: { - '--input': { type: String, description: 'Input file' }, - '--output': { type: String, description: 'Output file' }, - '--watch': { - type: oneOf(String, Boolean), - description: 'Watch for changes and rebuild as needed', - }, - '--poll': { - type: Boolean, - description: 'Use polling instead of filesystem events when watching', - }, - '--content': { - type: String, - description: 'Content paths to use for removing unused classes', - }, - '--minify': { type: Boolean, description: 'Minify the output' }, - '--config': { - type: String, - description: 'Path to a custom config file', - }, - '-c': '--config', - '-i': '--input', - '-o': '--output', - '-m': '--minify', - '-w': '--watch', - '-p': '--poll', - }, - }, -} - -let sharedFlags = { - '--help': { type: Boolean, description: 'Display usage information' }, - '-h': '--help', -} - -if ( - process.stdout.isTTY /* Detect redirecting output to a file */ && - (process.argv[2] === undefined || - process.argv.slice(2).every((flag) => sharedFlags[flag] !== undefined)) -) { - help({ - usage: [ - 'tailwindcss [--input input.css] [--output output.css] [--watch] [options...]', - 'tailwindcss init [--full] [options...]', - ], - commands: Object.keys(commands) - .filter((command) => command !== 'build') - .map((command) => `${command} [options]`), - options: { ...commands.build.args, ...sharedFlags }, - }) - process.exit(0) -} - -let command = ((arg = '') => (arg.startsWith('-') ? undefined : arg))(process.argv[2]) || 'build' - -if (commands[command] === undefined) { - if (fs.existsSync(path.resolve(command))) { - // TODO: Deprecate this in future versions - // Check if non-existing command, might be a file. - command = 'build' - } else { - help({ - message: `Invalid command: ${command}`, - usage: ['tailwindcss [options]'], - commands: Object.keys(commands) - .filter((command) => command !== 'build') - .map((command) => `${command} [options]`), - options: sharedFlags, - }) - process.exit(1) - } -} - -// Execute command -let { args: flags, run } = commands[command] -let args = (() => { - try { - let result = arg( - Object.fromEntries( - Object.entries({ ...flags, ...sharedFlags }) - .filter(([_key, value]) => !value?.type?.manualParsing) - .map(([key, value]) => [key, typeof value === 'object' ? value.type : value]) - ), - { permissive: true } - ) - - // Manual parsing of flags to allow for special flags like oneOf(Boolean, String) - for (let i = result['_'].length - 1; i >= 0; --i) { - let flag = result['_'][i] - if (!flag.startsWith('-')) continue - - let [flagName, flagValue] = flag.split('=') - let handler = flags[flagName] - - // Resolve flagName & handler - while (typeof handler === 'string') { - flagName = handler - handler = flags[handler] - } - - if (!handler) continue - - let args = [] - let offset = i + 1 - - // --flag value syntax was used so we need to pull `value` from `args` - if (flagValue === undefined) { - // Parse args for current flag - while (result['_'][offset] && !result['_'][offset].startsWith('-')) { - args.push(result['_'][offset++]) - } - - // Cleanup manually parsed flags + args - result['_'].splice(i, 1 + args.length) - - // No args were provided, use default value defined in handler - // One arg was provided, use that directly - // Multiple args were provided so pass them all in an array - flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args - } else { - // Remove the whole flag from the args array - result['_'].splice(i, 1) - } - - // Set the resolved value in the `result` object - result[flagName] = handler.type(flagValue, flagName) - } - - // Ensure that the `command` is always the first argument in the `args`. - // This is important so that we don't have to check if a default command - // (build) was used or not from within each plugin. - // - // E.g.: tailwindcss input.css -> _: ['build', 'input.css'] - // E.g.: tailwindcss build input.css -> _: ['build', 'input.css'] - if (result['_'][0] !== command) { - result['_'].unshift(command) - } - - return result - } catch (err) { - if (err.code === 'ARG_UNKNOWN_OPTION') { - help({ - message: err.message, - usage: ['tailwindcss [options]'], - options: sharedFlags, - }) - process.exit(1) - } - throw err - } -})() - -if (args['--help']) { - help({ - options: { ...flags, ...sharedFlags }, - usage: [`tailwindcss ${command} [options]`], - }) - process.exit(0) -} - -run(args) diff --git a/src/oxide/cli/init/index.ts b/src/oxide/cli/init/index.ts deleted file mode 100644 index ed69be95b..000000000 --- a/src/oxide/cli/init/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -import fs from 'fs' -import path from 'path' - -function isESM() { - const pkgPath = path.resolve('./package.json') - - try { - let pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) - return pkg.type && pkg.type === 'module' - } catch (err) { - return false - } -} - -export function init(args) { - let messages: string[] = [] - - let isProjectESM = args['--ts'] || args['--esm'] || isESM() - let syntax = args['--ts'] ? 'ts' : isProjectESM ? 'js' : 'cjs' - let extension = args['--ts'] ? 'ts' : 'js' - - let tailwindConfigLocation = path.resolve(args['_'][1] ?? `./tailwind.config.${extension}`) - - if (fs.existsSync(tailwindConfigLocation)) { - messages.push(`${path.basename(tailwindConfigLocation)} already exists.`) - } else { - let stubContentsFile = fs.readFileSync( - args['--full'] - ? path.resolve(__dirname, '../../../../stubs/config.full.js') - : path.resolve(__dirname, '../../../../stubs/config.simple.js'), - 'utf8' - ) - - let stubFile = fs.readFileSync( - path.resolve(__dirname, `../../../../stubs/tailwind.config.${syntax}`), - 'utf8' - ) - - // Drop `content` in the oxide engine to promote auto content - if (__OXIDE__) { - stubContentsFile = stubContentsFile.replace(/ *content: \[\],\n/, '') - } - - // Change colors import - stubContentsFile = stubContentsFile.replace('../colors', 'tailwindcss/colors') - - // Replace contents of {ts,js,cjs} file with the stub {simple,full}. - stubFile = - stubFile - .replace('__CONFIG__', stubContentsFile.replace('module.exports =', '').trim()) - .trim() + '\n\n' - - fs.writeFileSync(tailwindConfigLocation, stubFile, 'utf8') - - messages.push(`Created Tailwind CSS config file: ${path.basename(tailwindConfigLocation)}`) - } - - if (messages.length > 0) { - console.log() - for (let message of messages) { - console.log(message) - } - } -} diff --git a/src/oxide/postcss-plugin.ts b/src/oxide/postcss-plugin.ts deleted file mode 100644 index 1be3203f9..000000000 --- a/src/oxide/postcss-plugin.ts +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('../plugin.js') diff --git a/src/plugin.js b/src/plugin.js index 86f39d962..bfcdc6583 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -1,3 +1,6 @@ +import postcss from 'postcss' +import lightningcss from 'lightningcss' +import browserslist from 'browserslist' import setupTrackingContext from './lib/setupTrackingContext' import processTailwindFeatures from './processTailwindFeatures' import { env } from './lib/sharedState' @@ -14,7 +17,7 @@ module.exports = function tailwindcss(configOrPath) { console.time('JIT TOTAL') return root }, - ...(__OXIDE__ ? handleImportAtRules() : []), + ...handleImportAtRules(), function (root, result) { // Use the path for the `@config` directive if it exists, otherwise use the // path for the file being processed @@ -36,66 +39,61 @@ module.exports = function tailwindcss(configOrPath) { processTailwindFeatures(context)(root, result) }, - __OXIDE__ && - function lightningCssPlugin(_root, result) { - let postcss = require('postcss') - let lightningcss = require('lightningcss') - let browserslist = require('browserslist') + function lightningCssPlugin(_root, result) { + try { + let transformed = lightningcss.transform({ + filename: result.opts.from, + code: Buffer.from(result.root.toString()), + minify: false, + sourceMap: !!result.map, + inputSourceMap: result.map ? result.map.toString() : undefined, + targets: + typeof process !== 'undefined' && process.env.JEST_WORKER_ID + ? { chrome: 106 << 16 } + : lightningcss.browserslistToTargets( + browserslist(require('../package.json').browserslist) + ), - try { - let transformed = lightningcss.transform({ - filename: result.opts.from, - code: Buffer.from(result.root.toString()), - minify: false, - sourceMap: !!result.map, - inputSourceMap: result.map ? result.map.toString() : undefined, - targets: - typeof process !== 'undefined' && process.env.JEST_WORKER_ID - ? { chrome: 106 << 16 } - : lightningcss.browserslistToTargets( - browserslist(require('../package.json').browserslist) - ), + drafts: { + nesting: true, + customMedia: true, + }, + }) - drafts: { - nesting: true, - customMedia: true, - }, - }) + result.map = Object.assign(result.map ?? {}, { + toJSON() { + return transformed.map.toJSON() + }, + toString() { + return transformed.map.toString() + }, + }) - result.map = Object.assign(result.map ?? {}, { - toJSON() { - return transformed.map.toJSON() - }, - toString() { - return transformed.map.toString() - }, - }) - - result.root = postcss.parse(transformed.code.toString('utf8')) - } catch (err) { - if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { - let lines = err.source.split('\n') - err = new Error( - [ - 'Error formatting using Lightning CSS:', - '', - ...[ - '```css', - ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), - ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), - ...lines.slice(err.loc.line, err.loc.line + 2), - '```', - ], - ].join('\n') - ) - } - - if (Error.captureStackTrace) { - Error.captureStackTrace(err, lightningCssPlugin) - } - throw err + result.root = postcss.parse(transformed.code.toString('utf8')) + } catch (err) { + if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { + let lines = err.source.split('\n') + err = new Error( + [ + 'Error formatting using Lightning CSS:', + '', + ...[ + '```css', + ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), + ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), + ...lines.slice(err.loc.line, err.loc.line + 2), + '```', + ], + ].join('\n') + ) } - }, + + if (Error.captureStackTrace) { + Error.captureStackTrace(err, lightningCssPlugin) + } + throw err + } + }, env.DEBUG && function (root) { console.timeEnd('JIT TOTAL') diff --git a/src/util/getAllConfigs.js b/src/util/getAllConfigs.js index 90a20e11a..ce3665b97 100644 --- a/src/util/getAllConfigs.js +++ b/src/util/getAllConfigs.js @@ -2,14 +2,7 @@ import defaultFullConfig from '../../stubs/config.full.js' import { flagEnabled } from '../featureFlags' export default function getAllConfigs(config) { - const configs = ( - config?.presets ?? [ - __OXIDE__ - ? // Drop `content` in the oxide engine to promote auto content - Object.assign({}, defaultFullConfig, { content: 'auto' }) - : defaultFullConfig, - ] - ) + const configs = (config?.presets ?? [defaultFullConfig]) .slice() .reverse() .flatMap((preset) => getAllConfigs(preset instanceof Function ? preset() : preset)) diff --git a/src/util/log.js b/src/util/log.js index 0df5c8719..900c2d53f 100644 --- a/src/util/log.js +++ b/src/util/log.js @@ -17,6 +17,30 @@ export function dim(input) { } export default { + group(key, cb) { + if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) return + + if (key && alreadyShown.has(key)) return + if (key) alreadyShown.add(key) + + console.warn('') + + cb({ + info(messages) { + messages.forEach((message) => console.warn(colors.bold(colors.cyan('info')), '-', message)) + }, + warn(messages) { + messages.forEach((message) => + console.warn(colors.bold(colors.yellow('warn')), '-', message) + ) + }, + risk(messages) { + messages.forEach((message) => + console.warn(colors.bold(colors.magenta('risk')), '-', message) + ) + }, + }) + }, info(key, messages) { log(colors.bold(colors.cyan('info')), ...(Array.isArray(key) ? [key] : [messages, key])) }, diff --git a/src/util/normalizeConfig.js b/src/util/normalizeConfig.js index a79aaefd0..3cb98511c 100644 --- a/src/util/normalizeConfig.js +++ b/src/util/normalizeConfig.js @@ -185,31 +185,6 @@ export function normalizeConfig(config) { config.prefix = config.prefix ?? '' } - let auto = (() => { - // Config still has a `purge` option (for backwards compatibility), auto content should not be - // used - if (config.purge) return false - - // - if (config.content === 'auto') return true - - // We don't have content at all, auto content should be used - if (config.content === undefined) return true - - // We do have content as an object, but we don't have any files defined, auto content should - // be used - if ( - typeof config.content === 'object' && - config.content !== null && - !Array.isArray(config.content) - ) { - return config.content.files === undefined - } - - // We do have content defined, auto content should not be used - return false - })() - // Normalize the `content` config.content = { relative: (() => { @@ -222,20 +197,23 @@ export function normalizeConfig(config) { return flagEnabled(config, 'relativeContentPathsByDefault') })(), - files: auto - ? 'auto' - : (() => { - let { content, purge } = config + files: (() => { + let { content, purge } = config - if (content === undefined && purge === undefined) return [] - if (Array.isArray(purge)) return purge - if (Array.isArray(purge?.content)) return purge.content - if (Array.isArray(content)) return content - if (Array.isArray(content?.content)) return content.content - if (Array.isArray(content?.files)) return content.files + if (content === undefined && purge === undefined) return [] + if (purge) { + if (Array.isArray(purge)) return purge + if (Array.isArray(purge?.content)) return purge.content + return [] + } - return [] - })(), + if (Array.isArray(content)) return content + if (Array.isArray(content?.content)) return content.content + if (Array.isArray(content?.files)) return content.files + if (content === 'auto') return ['auto'] + + return [] + })(), extract: (() => { let extract = (() => { diff --git a/src/util/pluginUtils.js b/src/util/pluginUtils.js index bef9fc165..d4df12286 100644 --- a/src/util/pluginUtils.js +++ b/src/util/pluginUtils.js @@ -18,7 +18,6 @@ import { } from './dataTypes' import negateValue from './negateValue' import { backgroundSize } from './validateFormalSyntax' -import { flagEnabled } from '../featureFlags.js' /** * @param {import('postcss-selector-parser').Container} selectors @@ -243,12 +242,9 @@ export function coerceValue(types, modifier, options, tailwindConfig) { * @returns {Iterator<[value: string, type: string, modifier: string | null]>} */ export function* getMatchingTypes(types, rawModifier, options, tailwindConfig) { - let modifiersEnabled = flagEnabled(tailwindConfig, 'generalizedModifiers') - let [modifier, utilityModifier] = splitUtilityModifier(rawModifier) let canUseUtilityModifier = - modifiersEnabled && options.modifiers != null && (options.modifiers === 'any' || (typeof options.modifiers === 'object' && diff --git a/src/util/validateConfig.js b/src/util/validateConfig.js index dfba01844..ebd63d2d2 100644 --- a/src/util/validateConfig.js +++ b/src/util/validateConfig.js @@ -1,7 +1,8 @@ +import pc from 'picocolors' import log from './log' export function validateConfig(config) { - if (config.content.files !== 'auto' && config.content.files.length === 0) { + if (config.content.files.length === 0) { log.warn('content-problems', [ 'The `content` option in your Tailwind CSS configuration is missing or empty.', 'Configure your content sources or your generated CSS will be missing styles.', @@ -9,11 +10,13 @@ export function validateConfig(config) { ]) } - if (config.content.files === 'auto') { - log.warn('auto-content-experimental', [ - 'Automatic content detection in Tailwind CSS is currently in experimental preview.', - 'Preview features are not covered by semver, and may change at any time.', - ]) + if (config.content.files.includes('auto')) { + log.group('auto-content-experimental', (log) => { + log.info([pc.bold('Automatically detecting Tailwind CSS content sources...')]) + log.warn([ + 'Automatic content detection is experimental, and the behavior may change at any time.', + ]) + }) } // Warn if the line-clamp plugin is installed diff --git a/stubs/config.full.js b/stubs/config.full.js index 2dd01c6fd..965d2874a 100644 --- a/stubs/config.full.js +++ b/stubs/config.full.js @@ -1,5 +1,5 @@ module.exports = { - content: [], + content: ['auto'], presets: [], darkMode: 'media', // or 'class' theme: { diff --git a/stubs/config.simple.js b/stubs/config.simple.js index 9843c0557..3e0d35604 100644 --- a/stubs/config.simple.js +++ b/stubs/config.simple.js @@ -1,5 +1,5 @@ module.exports = { - content: [], + content: ['auto'], theme: { extend: {}, }, diff --git a/stubs/postcss.config.cjs b/stubs/postcss.config.cjs index 33ad091d2..08a01d4d1 100644 --- a/stubs/postcss.config.cjs +++ b/stubs/postcss.config.cjs @@ -1,6 +1,5 @@ module.exports = { plugins: { tailwindcss: {}, - autoprefixer: {}, }, } diff --git a/stubs/postcss.config.js b/stubs/postcss.config.js index 2e7af2b7f..284180207 100644 --- a/stubs/postcss.config.js +++ b/stubs/postcss.config.js @@ -1,6 +1,5 @@ export default { plugins: { tailwindcss: {}, - autoprefixer: {}, }, } diff --git a/tests/animations.test.js b/tests/animations.test.js index 958f24252..ab2467476 100644 --- a/tests/animations.test.js +++ b/tests/animations.test.js @@ -1,278 +1,276 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('basic', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .animate-spin { - animation: 1s linear infinite spin; - } - @keyframes ping { - 75%, - 100% { - opacity: 0; - transform: scale(2); - } - } - .hover\:animate-ping:hover { - animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; - } - @keyframes bounce { - 0%, - 100% { - animation-timing-function: cubic-bezier(0.8, 0, 1, 1); - transform: translateY(-25%); - } - 50% { - animation-timing-function: cubic-bezier(0, 0, 0.2, 1); - transform: none; - } - } - .group:hover .group-hover\:animate-bounce { - animation: 1s infinite bounce; - } - `) - }) - }) - - test('custom', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - keyframes: { - one: { to: { transform: 'rotate(360deg)' } }, - }, - animation: { - one: 'one 2s', - }, - }, +test('basic', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, }, - } + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes one { - to { - transform: rotate(360deg); - } + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes spin { + to { + transform: rotate(360deg); } - .animate-one { - animation: 2s one; + } + .animate-spin { + animation: 1s linear infinite spin; + } + @keyframes ping { + 75%, + 100% { + opacity: 0; + transform: scale(2); } - `) - }) - }) - - test('custom prefixed', () => { - let config = { - prefix: 'tw-', - content: [{ raw: `
` }], - theme: { - extend: { - keyframes: { - one: { to: { transform: 'rotate(360deg)' } }, - }, - animation: { - one: 'one 2s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes tw-one { - to { - transform: rotate(360deg); - } + } + .hover\:animate-ping:hover { + animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; + } + @keyframes bounce { + 0%, + 100% { + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + transform: translateY(-25%); } - .tw-animate-one { - animation: 2s tw-one; + 50% { + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + transform: none; } - `) - }) - }) - - test('multiple', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - animation: { - multiple: 'bounce 2s linear, pulse 3s ease-in', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes bounce { - 0%, - 100% { - animation-timing-function: cubic-bezier(0.8, 0, 1, 1); - transform: translateY(-25%); - } - 50% { - animation-timing-function: cubic-bezier(0, 0, 0.2, 1); - transform: none; - } - } - @keyframes pulse { - 50% { - opacity: 0.5; - } - } - .animate-multiple { - animation: 2s linear bounce, 3s ease-in pulse; - } - `) - }) - }) - - test('multiple custom', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - keyframes: { - one: { to: { transform: 'rotate(360deg)' } }, - two: { to: { transform: 'scale(1.23)' } }, - }, - animation: { - multiple: 'one 2s, two 3s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes one { - to { - transform: rotate(360deg); - } - } - @keyframes two { - to { - transform: scale(1.23); - } - } - .animate-multiple { - animation: 2s one, 3s two; - } - `) - }) - }) - - test('with dots in the name', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - theme: { - extend: { - keyframes: { - 'zoom-.5': { to: { transform: 'scale(0.5)' } }, - 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, - }, - animation: { - 'zoom-.5': 'zoom-.5 2s', - 'zoom-1.5': 'zoom-1.5 2s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes zoom-\.5 { - to { - transform: scale(0.5); - } - } - .animate-zoom-\.5 { - animation: 2s zoom-\.5; - } - @keyframes zoom-1\.5 { - to { - transform: scale(1.5); - } - } - .animate-zoom-1\.5 { - animation: 2s zoom-1\.5; - } - `) - }) - }) - - test('with dots in the name and prefix', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: html` -
-
- `, - }, - ], - theme: { - extend: { - keyframes: { - 'zoom-.5': { to: { transform: 'scale(0.5)' } }, - 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, - }, - animation: { - 'zoom-.5': 'zoom-.5 2s', - 'zoom-1.5': 'zoom-1.5 2s', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes tw-zoom-\.5 { - to { - transform: scale(0.5); - } - } - .tw-animate-zoom-\.5 { - animation: 2s tw-zoom-\.5; - } - @keyframes tw-zoom-1\.5 { - to { - transform: scale(1.5); - } - } - .tw-animate-zoom-1\.5 { - animation: 2s tw-zoom-1\.5; - } - `) - }) + } + .group:hover .group-hover\:animate-bounce { + animation: 1s infinite bounce; + } + `) + }) +}) + +test('custom', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + keyframes: { + one: { to: { transform: 'rotate(360deg)' } }, + }, + animation: { + one: 'one 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes one { + to { + transform: rotate(360deg); + } + } + .animate-one { + animation: 2s one; + } + `) + }) +}) + +test('custom prefixed', () => { + let config = { + prefix: 'tw-', + content: [{ raw: `
` }], + theme: { + extend: { + keyframes: { + one: { to: { transform: 'rotate(360deg)' } }, + }, + animation: { + one: 'one 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes tw-one { + to { + transform: rotate(360deg); + } + } + .tw-animate-one { + animation: 2s tw-one; + } + `) + }) +}) + +test('multiple', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + animation: { + multiple: 'bounce 2s linear, pulse 3s ease-in', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes bounce { + 0%, + 100% { + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + transform: translateY(-25%); + } + 50% { + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + transform: none; + } + } + @keyframes pulse { + 50% { + opacity: 0.5; + } + } + .animate-multiple { + animation: 2s linear bounce, 3s ease-in pulse; + } + `) + }) +}) + +test('multiple custom', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + keyframes: { + one: { to: { transform: 'rotate(360deg)' } }, + two: { to: { transform: 'scale(1.23)' } }, + }, + animation: { + multiple: 'one 2s, two 3s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes one { + to { + transform: rotate(360deg); + } + } + @keyframes two { + to { + transform: scale(1.23); + } + } + .animate-multiple { + animation: 2s one, 3s two; + } + `) + }) +}) + +test('with dots in the name', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + theme: { + extend: { + keyframes: { + 'zoom-.5': { to: { transform: 'scale(0.5)' } }, + 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, + }, + animation: { + 'zoom-.5': 'zoom-.5 2s', + 'zoom-1.5': 'zoom-1.5 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes zoom-\.5 { + to { + transform: scale(0.5); + } + } + .animate-zoom-\.5 { + animation: 2s zoom-\.5; + } + @keyframes zoom-1\.5 { + to { + transform: scale(1.5); + } + } + .animate-zoom-1\.5 { + animation: 2s zoom-1\.5; + } + `) + }) +}) + +test('with dots in the name and prefix', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: html` +
+
+ `, + }, + ], + theme: { + extend: { + keyframes: { + 'zoom-.5': { to: { transform: 'scale(0.5)' } }, + 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, + }, + animation: { + 'zoom-.5': 'zoom-.5 2s', + 'zoom-1.5': 'zoom-1.5 2s', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes tw-zoom-\.5 { + to { + transform: scale(0.5); + } + } + .tw-animate-zoom-\.5 { + animation: 2s tw-zoom-\.5; + } + @keyframes tw-zoom-1\.5 { + to { + transform: scale(1.5); + } + } + .tw-animate-zoom-1\.5 { + animation: 2s tw-zoom-1\.5; + } + `) }) }) diff --git a/tests/any-type.test.js b/tests/any-type.test.js index 7b7873966..34844f2c2 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -1,1307 +1,760 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - // Hi there, so you are debugging this test because something failed... right? Well we can look into - // the future and guessed that this would happen. So basically it means that we (it was probably - // you, silly) introduced a new plugin that conflicts with an existing plugin that has (either - // implicit or explicit) an `any` type. - // - // Now it is your job to decide which one should win, and mark that one with - // ```diff - // - 'any' - // + ['any', { preferOnConflict: true }] - // ``` - // in the corePlugins.js file. - // - // You probably want to let the original one win for backwards compatible reasons. - // - // Good luck! - test('any types are set on correct plugins', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +// Hi there, so you are debugging this test because something failed... right? Well we can look into +// the future and guessed that this would happen. So basically it means that we (it was probably +// you, silly) introduced a new plugin that conflicts with an existing plugin that has (either +// implicit or explicit) an `any` type. +// +// Now it is your job to decide which one should win, and mark that one with +// ```diff +// - 'any' +// + ['any', { preferOnConflict: true }] +// ``` +// in the corePlugins.js file. +// +// You probably want to let the original one win for backwards compatible reasons. +// +// Good luck! +test('any types are set on correct plugins', () => { + let config = { + future: { + logicalSiblingUtilities: false, + disableColorOpacityUtilitiesByDefault: false, + }, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - oxide.expect(result.css).toMatchFormattedCss(css` - .inset-\[var\(--any-value\)\] { - inset: var(--any-value); - } - .inset-x-\[var\(--any-value\)\] { - left: var(--any-value); - right: var(--any-value); - } - .inset-y-\[var\(--any-value\)\] { - top: var(--any-value); - bottom: var(--any-value); - } - .bottom-\[var\(--any-value\)\] { - bottom: var(--any-value); - } - .left-\[var\(--any-value\)\] { - left: var(--any-value); - } - .right-\[var\(--any-value\)\] { - right: var(--any-value); - } - .top-\[var\(--any-value\)\] { - top: var(--any-value); - } - .z-\[var\(--any-value\)\] { - z-index: var(--any-value); - } - .order-\[var\(--any-value\)\] { - order: var(--any-value); - } - .col-\[var\(--any-value\)\] { - grid-column: var(--any-value); - } - .col-start-\[var\(--any-value\)\] { - grid-column-start: var(--any-value); - } - .col-end-\[var\(--any-value\)\] { - grid-column-end: var(--any-value); - } - .row-\[var\(--any-value\)\] { - grid-row: var(--any-value); - } - .row-start-\[var\(--any-value\)\] { - grid-row-start: var(--any-value); - } - .row-end-\[var\(--any-value\)\] { - grid-row-end: var(--any-value); - } - .m-\[var\(--any-value\)\] { - margin: var(--any-value); - } - .mx-\[var\(--any-value\)\] { - margin-left: var(--any-value); - margin-right: var(--any-value); - } - .my-\[var\(--any-value\)\] { - margin-top: var(--any-value); - margin-bottom: var(--any-value); - } - .mb-\[var\(--any-value\)\] { - margin-bottom: var(--any-value); - } - .ml-\[var\(--any-value\)\] { - margin-left: var(--any-value); - } - .mr-\[var\(--any-value\)\] { - margin-right: var(--any-value); - } - .mt-\[var\(--any-value\)\] { - margin-top: var(--any-value); - } - .aspect-\[var\(--any-value\)\] { - aspect-ratio: var(--any-value); - } - .h-\[var\(--any-value\)\] { - height: var(--any-value); - } - .max-h-\[var\(--any-value\)\] { - max-height: var(--any-value); - } - .min-h-\[var\(--any-value\)\] { - min-height: var(--any-value); - } - .w-\[var\(--any-value\)\] { - width: var(--any-value); - } - .min-w-\[var\(--any-value\)\] { - min-width: var(--any-value); - } - .max-w-\[var\(--any-value\)\] { - max-width: var(--any-value); - } - .flex-\[var\(--any-value\)\] { - flex: var(--any-value); - } - .flex-shrink-\[var\(--any-value\)\], - .shrink-\[var\(--any-value\)\] { - flex-shrink: var(--any-value); - } - .flex-grow-\[var\(--any-value\)\], - .grow-\[var\(--any-value\)\] { - flex-grow: var(--any-value); - } - .basis-\[var\(--any-value\)\] { - flex-basis: var(--any-value); - } - .border-spacing-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-x-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-y-\[var\(--any-value\)\] { - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .origin-\[var\(--any-value\)\] { - transform-origin: var(--any-value); - } - .translate-x-\[var\(--any-value\)\] { - --tw-translate-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .translate-y-\[var\(--any-value\)\] { - --tw-translate-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .rotate-\[var\(--any-value\)\] { - --tw-rotate: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-x-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-y-\[var\(--any-value\)\] { - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .animate-\[var\(--any-value\)\] { - animation: var(--any-value); - } - .cursor-\[var\(--any-value\)\] { - cursor: var(--any-value); - } - .scroll-m-\[var\(--any-value\)\] { - scroll-margin: var(--any-value); - } - .scroll-mx-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - scroll-margin-right: var(--any-value); - } - .scroll-my-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - scroll-margin-bottom: var(--any-value); - } - .scroll-mb-\[var\(--any-value\)\] { - scroll-margin-bottom: var(--any-value); - } - .scroll-ml-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - } - .scroll-mr-\[var\(--any-value\)\] { - scroll-margin-right: var(--any-value); - } - .scroll-mt-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - } - .scroll-p-\[var\(--any-value\)\] { - scroll-padding: var(--any-value); - } - .scroll-px-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - scroll-padding-right: var(--any-value); - } - .scroll-py-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - scroll-padding-bottom: var(--any-value); - } - .scroll-pb-\[var\(--any-value\)\] { - scroll-padding-bottom: var(--any-value); - } - .scroll-pl-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - } - .scroll-pr-\[var\(--any-value\)\] { - scroll-padding-right: var(--any-value); - } - .scroll-pt-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - } - .list-\[var\(--any-value\)\] { - list-style-type: var(--any-value); - } - .columns-\[var\(--any-value\)\] { - columns: var(--any-value); - } - .auto-cols-\[var\(--any-value\)\] { - grid-auto-columns: var(--any-value); - } - .auto-rows-\[var\(--any-value\)\] { - grid-auto-rows: var(--any-value); - } - .grid-cols-\[var\(--any-value\)\] { - grid-template-columns: var(--any-value); - } - .grid-rows-\[var\(--any-value\)\] { - grid-template-rows: var(--any-value); - } - .gap-\[var\(--any-value\)\] { - gap: var(--any-value); - } - .gap-x-\[var\(--any-value\)\] { - column-gap: var(--any-value); - } - .gap-y-\[var\(--any-value\)\] { - row-gap: var(--any-value); - } - .space-x-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(var(--any-value) * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(var(--any-value) * var(--tw-space-x-reverse)); - } - .space-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(var(--any-value) * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(var(--any-value) * var(--tw-space-y-reverse)); - } - .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); - } - .divide-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: var(--any-value); - } - .rounded-\[var\(--any-value\)\] { - border-radius: var(--any-value); - } - .rounded-b-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-l-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-r-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - border-bottom-right-radius: var(--any-value); - } - .rounded-t-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-top-right-radius: var(--any-value); - } - .rounded-bl-\[var\(--any-value\)\] { - border-bottom-left-radius: var(--any-value); - } - .rounded-br-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - } - .rounded-tl-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - } - .rounded-tr-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - } - .border-\[var\(--any-value\)\] { - border-color: var(--any-value); - } - .border-x-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - border-right-color: var(--any-value); - } - .border-y-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - border-bottom-color: var(--any-value); - } - .border-b-\[var\(--any-value\)\] { - border-bottom-color: var(--any-value); - } - .border-l-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - } - .border-r-\[var\(--any-value\)\] { - border-right-color: var(--any-value); - } - .border-t-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - } - .bg-\[var\(--any-value\)\] { - background-color: var(--any-value); - } - .from-\[var\(--any-value\)\] { - --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-\[var\(--any-value\)\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), - var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); - } - .to-\[var\(--any-value\)\] { - --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); - } - .fill-\[var\(--any-value\)\] { - fill: var(--any-value); - } - .stroke-\[var\(--any-value\)\] { - stroke: var(--any-value); - } - .object-\[var\(--any-value\)\] { - object-position: var(--any-value); - } - .p-\[var\(--any-value\)\] { - padding: var(--any-value); - } - .px-\[var\(--any-value\)\] { - padding-left: var(--any-value); - padding-right: var(--any-value); - } - .py-\[var\(--any-value\)\] { - padding-top: var(--any-value); - padding-bottom: var(--any-value); - } - .pb-\[var\(--any-value\)\] { - padding-bottom: var(--any-value); - } - .pl-\[var\(--any-value\)\] { - padding-left: var(--any-value); - } - .pr-\[var\(--any-value\)\] { - padding-right: var(--any-value); - } - .pt-\[var\(--any-value\)\] { - padding-top: var(--any-value); - } - .indent-\[var\(--any-value\)\] { - text-indent: var(--any-value); - } - .align-\[var\(--any-value\)\] { - vertical-align: var(--any-value); - } - .font-\[var\(--any-value\)\] { - font-weight: var(--any-value); - } - .leading-\[var\(--any-value\)\] { - line-height: var(--any-value); - } - .tracking-\[var\(--any-value\)\] { - letter-spacing: var(--any-value); - } - .text-\[var\(--any-value\)\] { - color: var(--any-value); - } - .decoration-\[var\(--any-value\)\] { - text-decoration-color: var(--any-value); - } - .underline-offset-\[var\(--any-value\)\] { - text-underline-offset: var(--any-value); - } - .placeholder-\[var\(--any-value\)\]::placeholder { - color: var(--any-value); - } - .caret-\[var\(--any-value\)\] { - caret-color: var(--any-value); - } - .accent-\[var\(--any-value\)\] { - accent-color: var(--any-value); - } - .opacity-\[var\(--any-value\)\] { - opacity: var(--any-value); - } - .shadow-\[var\(--any-value\)\] { - --tw-shadow-color: var(--any-value); - --tw-shadow: var(--tw-shadow-colored); - } - .outline-offset-\[var\(--any-value\)\] { - outline-offset: var(--any-value); - } - .outline-\[var\(--any-value\)\] { - outline-color: var(--any-value); - } - .ring-\[var\(--any-value\)\] { - --tw-ring-color: var(--any-value); - } - .ring-offset-\[var\(--any-value\)\] { - --tw-ring-offset-color: var(--any-value); - } - .blur-\[var\(--any-value\)\] { - --tw-blur: blur(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .brightness-\[var\(--any-value\)\] { - --tw-brightness: brightness(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .contrast-\[var\(--any-value\)\] { - --tw-contrast: contrast(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .drop-shadow-\[var\(--any-value\)\] { - --tw-drop-shadow: drop-shadow(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .grayscale-\[var\(--any-value\)\] { - --tw-grayscale: grayscale(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .hue-rotate-\[var\(--any-value\)\] { - --tw-hue-rotate: hue-rotate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .invert-\[var\(--any-value\)\] { - --tw-invert: invert(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .saturate-\[var\(--any-value\)\] { - --tw-saturate: saturate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .sepia-\[var\(--any-value\)\] { - --tw-sepia: sepia(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .backdrop-blur-\[var\(--any-value\)\] { - --tw-backdrop-blur: blur(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-brightness-\[var\(--any-value\)\] { - --tw-backdrop-brightness: brightness(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-contrast-\[var\(--any-value\)\] { - --tw-backdrop-contrast: contrast(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-grayscale-\[var\(--any-value\)\] { - --tw-backdrop-grayscale: grayscale(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-hue-rotate-\[var\(--any-value\)\] { - --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-invert-\[var\(--any-value\)\] { - --tw-backdrop-invert: invert(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-opacity-\[var\(--any-value\)\] { - --tw-backdrop-opacity: opacity(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-saturate-\[var\(--any-value\)\] { - --tw-backdrop-saturate: saturate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-sepia-\[var\(--any-value\)\] { - --tw-backdrop-sepia: sepia(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .transition-\[var\(--any-value\)\] { - transition-property: var(--any-value); - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - .delay-\[var\(--any-value\)\] { - transition-delay: var(--any-value); - } - .duration-\[var\(--any-value\)\] { - transition-duration: var(--any-value); - } - .ease-\[var\(--any-value\)\] { - transition-timing-function: var(--any-value); - } - .will-change-\[var\(--any-value\)\] { - will-change: var(--any-value); - } - .content-\[var\(--any-value\)\] { - --tw-content: var(--any-value); - content: var(--tw-content); - } - `) - stable.expect(result.css).toMatchFormattedCss(css` - .inset-\[var\(--any-value\)\] { - inset: var(--any-value); - } - .inset-x-\[var\(--any-value\)\] { - left: var(--any-value); - right: var(--any-value); - } - .inset-y-\[var\(--any-value\)\] { - top: var(--any-value); - bottom: var(--any-value); - } - .bottom-\[var\(--any-value\)\] { - bottom: var(--any-value); - } - .left-\[var\(--any-value\)\] { - left: var(--any-value); - } - .right-\[var\(--any-value\)\] { - right: var(--any-value); - } - .top-\[var\(--any-value\)\] { - top: var(--any-value); - } - .z-\[var\(--any-value\)\] { - z-index: var(--any-value); - } - .order-\[var\(--any-value\)\] { - order: var(--any-value); - } - .col-\[var\(--any-value\)\] { - grid-column: var(--any-value); - } - .col-start-\[var\(--any-value\)\] { - grid-column-start: var(--any-value); - } - .col-end-\[var\(--any-value\)\] { - grid-column-end: var(--any-value); - } - .row-\[var\(--any-value\)\] { - grid-row: var(--any-value); - } - .row-start-\[var\(--any-value\)\] { - grid-row-start: var(--any-value); - } - .row-end-\[var\(--any-value\)\] { - grid-row-end: var(--any-value); - } - .m-\[var\(--any-value\)\] { - margin: var(--any-value); - } - .mx-\[var\(--any-value\)\] { - margin-left: var(--any-value); - margin-right: var(--any-value); - } - .my-\[var\(--any-value\)\] { - margin-top: var(--any-value); - margin-bottom: var(--any-value); - } - .mb-\[var\(--any-value\)\] { - margin-bottom: var(--any-value); - } - .ml-\[var\(--any-value\)\] { - margin-left: var(--any-value); - } - .mr-\[var\(--any-value\)\] { - margin-right: var(--any-value); - } - .mt-\[var\(--any-value\)\] { - margin-top: var(--any-value); - } - .aspect-\[var\(--any-value\)\] { - aspect-ratio: var(--any-value); - } - .h-\[var\(--any-value\)\] { - height: var(--any-value); - } - .max-h-\[var\(--any-value\)\] { - max-height: var(--any-value); - } - .min-h-\[var\(--any-value\)\] { - min-height: var(--any-value); - } - .w-\[var\(--any-value\)\] { - width: var(--any-value); - } - .min-w-\[var\(--any-value\)\] { - min-width: var(--any-value); - } - .max-w-\[var\(--any-value\)\] { - max-width: var(--any-value); - } - .flex-\[var\(--any-value\)\] { - flex: var(--any-value); - } - .flex-shrink-\[var\(--any-value\)\], - .shrink-\[var\(--any-value\)\] { - flex-shrink: var(--any-value); - } - .flex-grow-\[var\(--any-value\)\], - .grow-\[var\(--any-value\)\] { - flex-grow: var(--any-value); - } - .basis-\[var\(--any-value\)\] { - flex-basis: var(--any-value); - } - .border-spacing-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-x-\[var\(--any-value\)\] { - --tw-border-spacing-x: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .border-spacing-y-\[var\(--any-value\)\] { - --tw-border-spacing-y: var(--any-value); - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); - } - .origin-\[var\(--any-value\)\] { - transform-origin: var(--any-value); - } - .translate-x-\[var\(--any-value\)\] { - --tw-translate-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .translate-y-\[var\(--any-value\)\] { - --tw-translate-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .rotate-\[var\(--any-value\)\] { - --tw-rotate: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-x-\[var\(--any-value\)\] { - --tw-scale-x: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-y-\[var\(--any-value\)\] { - --tw-scale-y: var(--any-value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .animate-\[var\(--any-value\)\] { - animation: var(--any-value); - } - .cursor-\[var\(--any-value\)\] { - cursor: var(--any-value); - } - .scroll-m-\[var\(--any-value\)\] { - scroll-margin: var(--any-value); - } - .scroll-mx-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - scroll-margin-right: var(--any-value); - } - .scroll-my-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - scroll-margin-bottom: var(--any-value); - } - .scroll-mb-\[var\(--any-value\)\] { - scroll-margin-bottom: var(--any-value); - } - .scroll-ml-\[var\(--any-value\)\] { - scroll-margin-left: var(--any-value); - } - .scroll-mr-\[var\(--any-value\)\] { - scroll-margin-right: var(--any-value); - } - .scroll-mt-\[var\(--any-value\)\] { - scroll-margin-top: var(--any-value); - } - .scroll-p-\[var\(--any-value\)\] { - scroll-padding: var(--any-value); - } - .scroll-px-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - scroll-padding-right: var(--any-value); - } - .scroll-py-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - scroll-padding-bottom: var(--any-value); - } - .scroll-pb-\[var\(--any-value\)\] { - scroll-padding-bottom: var(--any-value); - } - .scroll-pl-\[var\(--any-value\)\] { - scroll-padding-left: var(--any-value); - } - .scroll-pr-\[var\(--any-value\)\] { - scroll-padding-right: var(--any-value); - } - .scroll-pt-\[var\(--any-value\)\] { - scroll-padding-top: var(--any-value); - } - .list-\[var\(--any-value\)\] { - list-style-type: var(--any-value); - } - .columns-\[var\(--any-value\)\] { - columns: var(--any-value); - } - .auto-cols-\[var\(--any-value\)\] { - grid-auto-columns: var(--any-value); - } - .auto-rows-\[var\(--any-value\)\] { - grid-auto-rows: var(--any-value); - } - .grid-cols-\[var\(--any-value\)\] { - grid-template-columns: var(--any-value); - } - .grid-rows-\[var\(--any-value\)\] { - grid-template-rows: var(--any-value); - } - .gap-\[var\(--any-value\)\] { - gap: var(--any-value); - } - .gap-x-\[var\(--any-value\)\] { - column-gap: var(--any-value); - } - .gap-y-\[var\(--any-value\)\] { - row-gap: var(--any-value); - } - .space-x-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(var(--any-value) * var(--tw-space-x-reverse)); - margin-left: calc(var(--any-value) * calc(1 - var(--tw-space-x-reverse))); - } - .space-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(var(--any-value) * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(var(--any-value) * var(--tw-space-y-reverse)); - } - .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); - } - .divide-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: var(--any-value); - } - .divide-opacity-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: var(--any-value); - } - .rounded-\[var\(--any-value\)\] { - border-radius: var(--any-value); - } - .rounded-b-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-l-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-bottom-left-radius: var(--any-value); - } - .rounded-r-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - border-bottom-right-radius: var(--any-value); - } - .rounded-t-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - border-top-right-radius: var(--any-value); - } - .rounded-bl-\[var\(--any-value\)\] { - border-bottom-left-radius: var(--any-value); - } - .rounded-br-\[var\(--any-value\)\] { - border-bottom-right-radius: var(--any-value); - } - .rounded-tl-\[var\(--any-value\)\] { - border-top-left-radius: var(--any-value); - } - .rounded-tr-\[var\(--any-value\)\] { - border-top-right-radius: var(--any-value); - } - .border-\[var\(--any-value\)\] { - border-color: var(--any-value); - } - .border-x-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - border-right-color: var(--any-value); - } - .border-y-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - border-bottom-color: var(--any-value); - } - .border-b-\[var\(--any-value\)\] { - border-bottom-color: var(--any-value); - } - .border-l-\[var\(--any-value\)\] { - border-left-color: var(--any-value); - } - .border-r-\[var\(--any-value\)\] { - border-right-color: var(--any-value); - } - .border-t-\[var\(--any-value\)\] { - border-top-color: var(--any-value); - } - .border-opacity-\[var\(--any-value\)\] { - --tw-border-opacity: var(--any-value); - } - .bg-\[var\(--any-value\)\] { - background-color: var(--any-value); - } - .bg-opacity-\[var\(--any-value\)\] { - --tw-bg-opacity: var(--any-value); - } - .from-\[var\(--any-value\)\] { - --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-\[var\(--any-value\)\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), - var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); - } - .to-\[var\(--any-value\)\] { - --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); - } - .fill-\[var\(--any-value\)\] { - fill: var(--any-value); - } - .stroke-\[var\(--any-value\)\] { - stroke: var(--any-value); - } - .object-\[var\(--any-value\)\] { - object-position: var(--any-value); - } - .p-\[var\(--any-value\)\] { - padding: var(--any-value); - } - .px-\[var\(--any-value\)\] { - padding-left: var(--any-value); - padding-right: var(--any-value); - } - .py-\[var\(--any-value\)\] { - padding-top: var(--any-value); - padding-bottom: var(--any-value); - } - .pb-\[var\(--any-value\)\] { - padding-bottom: var(--any-value); - } - .pl-\[var\(--any-value\)\] { - padding-left: var(--any-value); - } - .pr-\[var\(--any-value\)\] { - padding-right: var(--any-value); - } - .pt-\[var\(--any-value\)\] { - padding-top: var(--any-value); - } - .indent-\[var\(--any-value\)\] { - text-indent: var(--any-value); - } - .align-\[var\(--any-value\)\] { - vertical-align: var(--any-value); - } - .font-\[var\(--any-value\)\] { - font-weight: var(--any-value); - } - .leading-\[var\(--any-value\)\] { - line-height: var(--any-value); - } - .tracking-\[var\(--any-value\)\] { - letter-spacing: var(--any-value); - } - .text-\[var\(--any-value\)\] { - color: var(--any-value); - } - .text-opacity-\[var\(--any-value\)\] { - --tw-text-opacity: var(--any-value); - } - .decoration-\[var\(--any-value\)\] { - text-decoration-color: var(--any-value); - } - .underline-offset-\[var\(--any-value\)\] { - text-underline-offset: var(--any-value); - } - .placeholder-\[var\(--any-value\)\]::placeholder { - color: var(--any-value); - } - .placeholder-opacity-\[var\(--any-value\)\]::placeholder { - --tw-placeholder-opacity: var(--any-value); - } - .caret-\[var\(--any-value\)\] { - caret-color: var(--any-value); - } - .accent-\[var\(--any-value\)\] { - accent-color: var(--any-value); - } - .opacity-\[var\(--any-value\)\] { - opacity: var(--any-value); - } - .shadow-\[var\(--any-value\)\] { - --tw-shadow-color: var(--any-value); - --tw-shadow: var(--tw-shadow-colored); - } - .outline-offset-\[var\(--any-value\)\] { - outline-offset: var(--any-value); - } - .outline-\[var\(--any-value\)\] { - outline-color: var(--any-value); - } - .ring-\[var\(--any-value\)\] { - --tw-ring-color: var(--any-value); - } - .ring-opacity-\[var\(--any-value\)\] { - --tw-ring-opacity: var(--any-value); - } - .ring-offset-\[var\(--any-value\)\] { - --tw-ring-offset-color: var(--any-value); - } - .blur-\[var\(--any-value\)\] { - --tw-blur: blur(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .brightness-\[var\(--any-value\)\] { - --tw-brightness: brightness(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .contrast-\[var\(--any-value\)\] { - --tw-contrast: contrast(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .drop-shadow-\[var\(--any-value\)\] { - --tw-drop-shadow: drop-shadow(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .grayscale-\[var\(--any-value\)\] { - --tw-grayscale: grayscale(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .hue-rotate-\[var\(--any-value\)\] { - --tw-hue-rotate: hue-rotate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .invert-\[var\(--any-value\)\] { - --tw-invert: invert(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .saturate-\[var\(--any-value\)\] { - --tw-saturate: saturate(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .sepia-\[var\(--any-value\)\] { - --tw-sepia: sepia(var(--any-value)); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .backdrop-blur-\[var\(--any-value\)\] { - --tw-backdrop-blur: blur(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-brightness-\[var\(--any-value\)\] { - --tw-backdrop-brightness: brightness(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-contrast-\[var\(--any-value\)\] { - --tw-backdrop-contrast: contrast(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-grayscale-\[var\(--any-value\)\] { - --tw-backdrop-grayscale: grayscale(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-hue-rotate-\[var\(--any-value\)\] { - --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-invert-\[var\(--any-value\)\] { - --tw-backdrop-invert: invert(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-opacity-\[var\(--any-value\)\] { - --tw-backdrop-opacity: opacity(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-saturate-\[var\(--any-value\)\] { - --tw-backdrop-saturate: saturate(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .backdrop-sepia-\[var\(--any-value\)\] { - --tw-backdrop-sepia: sepia(var(--any-value)); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) - var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) - var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) - var(--tw-backdrop-sepia); - } - .transition-\[var\(--any-value\)\] { - transition-property: var(--any-value); - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - .delay-\[var\(--any-value\)\] { - transition-delay: var(--any-value); - } - .duration-\[var\(--any-value\)\] { - transition-duration: var(--any-value); - } - .ease-\[var\(--any-value\)\] { - transition-timing-function: var(--any-value); - } - .will-change-\[var\(--any-value\)\] { - will-change: var(--any-value); - } - .content-\[var\(--any-value\)\] { - --tw-content: var(--any-value); - content: var(--tw-content); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .inset-\[var\(--any-value\)\] { + inset: var(--any-value); + } + .inset-x-\[var\(--any-value\)\] { + left: var(--any-value); + right: var(--any-value); + } + .inset-y-\[var\(--any-value\)\] { + top: var(--any-value); + bottom: var(--any-value); + } + .bottom-\[var\(--any-value\)\] { + bottom: var(--any-value); + } + .left-\[var\(--any-value\)\] { + left: var(--any-value); + } + .right-\[var\(--any-value\)\] { + right: var(--any-value); + } + .top-\[var\(--any-value\)\] { + top: var(--any-value); + } + .z-\[var\(--any-value\)\] { + z-index: var(--any-value); + } + .order-\[var\(--any-value\)\] { + order: var(--any-value); + } + .col-\[var\(--any-value\)\] { + grid-column: var(--any-value); + } + .col-start-\[var\(--any-value\)\] { + grid-column-start: var(--any-value); + } + .col-end-\[var\(--any-value\)\] { + grid-column-end: var(--any-value); + } + .row-\[var\(--any-value\)\] { + grid-row: var(--any-value); + } + .row-start-\[var\(--any-value\)\] { + grid-row-start: var(--any-value); + } + .row-end-\[var\(--any-value\)\] { + grid-row-end: var(--any-value); + } + .m-\[var\(--any-value\)\] { + margin: var(--any-value); + } + .mx-\[var\(--any-value\)\] { + margin-left: var(--any-value); + margin-right: var(--any-value); + } + .my-\[var\(--any-value\)\] { + margin-top: var(--any-value); + margin-bottom: var(--any-value); + } + .mb-\[var\(--any-value\)\] { + margin-bottom: var(--any-value); + } + .ml-\[var\(--any-value\)\] { + margin-left: var(--any-value); + } + .mr-\[var\(--any-value\)\] { + margin-right: var(--any-value); + } + .mt-\[var\(--any-value\)\] { + margin-top: var(--any-value); + } + .aspect-\[var\(--any-value\)\] { + aspect-ratio: var(--any-value); + } + .h-\[var\(--any-value\)\] { + height: var(--any-value); + } + .max-h-\[var\(--any-value\)\] { + max-height: var(--any-value); + } + .min-h-\[var\(--any-value\)\] { + min-height: var(--any-value); + } + .w-\[var\(--any-value\)\] { + width: var(--any-value); + } + .min-w-\[var\(--any-value\)\] { + min-width: var(--any-value); + } + .max-w-\[var\(--any-value\)\] { + max-width: var(--any-value); + } + .flex-\[var\(--any-value\)\] { + flex: var(--any-value); + } + .flex-shrink-\[var\(--any-value\)\], + .shrink-\[var\(--any-value\)\] { + flex-shrink: var(--any-value); + } + .flex-grow-\[var\(--any-value\)\], + .grow-\[var\(--any-value\)\] { + flex-grow: var(--any-value); + } + .basis-\[var\(--any-value\)\] { + flex-basis: var(--any-value); + } + .border-spacing-\[var\(--any-value\)\] { + --tw-border-spacing-x: var(--any-value); + --tw-border-spacing-y: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .border-spacing-x-\[var\(--any-value\)\] { + --tw-border-spacing-x: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .border-spacing-y-\[var\(--any-value\)\] { + --tw-border-spacing-y: var(--any-value); + border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); + } + .origin-\[var\(--any-value\)\] { + transform-origin: var(--any-value); + } + .translate-x-\[var\(--any-value\)\] { + --tw-translate-x: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .translate-y-\[var\(--any-value\)\] { + --tw-translate-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .rotate-\[var\(--any-value\)\] { + --tw-rotate: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-\[var\(--any-value\)\] { + --tw-scale-x: var(--any-value); + --tw-scale-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-x-\[var\(--any-value\)\] { + --tw-scale-x: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .scale-y-\[var\(--any-value\)\] { + --tw-scale-y: var(--any-value); + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .animate-\[var\(--any-value\)\] { + animation: var(--any-value); + } + .cursor-\[var\(--any-value\)\] { + cursor: var(--any-value); + } + .scroll-m-\[var\(--any-value\)\] { + scroll-margin: var(--any-value); + } + .scroll-mx-\[var\(--any-value\)\] { + scroll-margin-left: var(--any-value); + scroll-margin-right: var(--any-value); + } + .scroll-my-\[var\(--any-value\)\] { + scroll-margin-top: var(--any-value); + scroll-margin-bottom: var(--any-value); + } + .scroll-mb-\[var\(--any-value\)\] { + scroll-margin-bottom: var(--any-value); + } + .scroll-ml-\[var\(--any-value\)\] { + scroll-margin-left: var(--any-value); + } + .scroll-mr-\[var\(--any-value\)\] { + scroll-margin-right: var(--any-value); + } + .scroll-mt-\[var\(--any-value\)\] { + scroll-margin-top: var(--any-value); + } + .scroll-p-\[var\(--any-value\)\] { + scroll-padding: var(--any-value); + } + .scroll-px-\[var\(--any-value\)\] { + scroll-padding-left: var(--any-value); + scroll-padding-right: var(--any-value); + } + .scroll-py-\[var\(--any-value\)\] { + scroll-padding-top: var(--any-value); + scroll-padding-bottom: var(--any-value); + } + .scroll-pb-\[var\(--any-value\)\] { + scroll-padding-bottom: var(--any-value); + } + .scroll-pl-\[var\(--any-value\)\] { + scroll-padding-left: var(--any-value); + } + .scroll-pr-\[var\(--any-value\)\] { + scroll-padding-right: var(--any-value); + } + .scroll-pt-\[var\(--any-value\)\] { + scroll-padding-top: var(--any-value); + } + .list-\[var\(--any-value\)\] { + list-style-type: var(--any-value); + } + .columns-\[var\(--any-value\)\] { + columns: var(--any-value); + } + .auto-cols-\[var\(--any-value\)\] { + grid-auto-columns: var(--any-value); + } + .auto-rows-\[var\(--any-value\)\] { + grid-auto-rows: var(--any-value); + } + .grid-cols-\[var\(--any-value\)\] { + grid-template-columns: var(--any-value); + } + .grid-rows-\[var\(--any-value\)\] { + grid-template-rows: var(--any-value); + } + .gap-\[var\(--any-value\)\] { + gap: var(--any-value); + } + .gap-x-\[var\(--any-value\)\] { + column-gap: var(--any-value); + } + .gap-y-\[var\(--any-value\)\] { + row-gap: var(--any-value); + } + .space-x-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(var(--any-value) * var(--tw-space-x-reverse)); + margin-left: calc(var(--any-value) * calc(1 - var(--tw-space-x-reverse))); + } + .space-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(var(--any-value) * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(var(--any-value) * var(--tw-space-y-reverse)); + } + .divide-y-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(var(--any-value) * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(var(--any-value) * var(--tw-divide-y-reverse)); + } + .divide-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: var(--any-value); + } + .divide-opacity-\[var\(--any-value\)\] > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: var(--any-value); + } + .rounded-\[var\(--any-value\)\] { + border-radius: var(--any-value); + } + .rounded-b-\[var\(--any-value\)\] { + border-bottom-right-radius: var(--any-value); + border-bottom-left-radius: var(--any-value); + } + .rounded-l-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + border-bottom-left-radius: var(--any-value); + } + .rounded-r-\[var\(--any-value\)\] { + border-top-right-radius: var(--any-value); + border-bottom-right-radius: var(--any-value); + } + .rounded-t-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + border-top-right-radius: var(--any-value); + } + .rounded-bl-\[var\(--any-value\)\] { + border-bottom-left-radius: var(--any-value); + } + .rounded-br-\[var\(--any-value\)\] { + border-bottom-right-radius: var(--any-value); + } + .rounded-tl-\[var\(--any-value\)\] { + border-top-left-radius: var(--any-value); + } + .rounded-tr-\[var\(--any-value\)\] { + border-top-right-radius: var(--any-value); + } + .border-\[var\(--any-value\)\] { + border-color: var(--any-value); + } + .border-x-\[var\(--any-value\)\] { + border-left-color: var(--any-value); + border-right-color: var(--any-value); + } + .border-y-\[var\(--any-value\)\] { + border-top-color: var(--any-value); + border-bottom-color: var(--any-value); + } + .border-b-\[var\(--any-value\)\] { + border-bottom-color: var(--any-value); + } + .border-l-\[var\(--any-value\)\] { + border-left-color: var(--any-value); + } + .border-r-\[var\(--any-value\)\] { + border-right-color: var(--any-value); + } + .border-t-\[var\(--any-value\)\] { + border-top-color: var(--any-value); + } + .border-opacity-\[var\(--any-value\)\] { + --tw-border-opacity: var(--any-value); + } + .bg-\[var\(--any-value\)\] { + background-color: var(--any-value); + } + .bg-opacity-\[var\(--any-value\)\] { + --tw-bg-opacity: var(--any-value); + } + .from-\[var\(--any-value\)\] { + --tw-gradient-from: var(--any-value) var(--tw-gradient-from-position); + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .via-\[var\(--any-value\)\] { + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), + var(--any-value) var(--tw-gradient-via-position), var(--tw-gradient-to); + } + .to-\[var\(--any-value\)\] { + --tw-gradient-to: var(--any-value) var(--tw-gradient-to-position); + } + .fill-\[var\(--any-value\)\] { + fill: var(--any-value); + } + .stroke-\[var\(--any-value\)\] { + stroke: var(--any-value); + } + .object-\[var\(--any-value\)\] { + object-position: var(--any-value); + } + .p-\[var\(--any-value\)\] { + padding: var(--any-value); + } + .px-\[var\(--any-value\)\] { + padding-left: var(--any-value); + padding-right: var(--any-value); + } + .py-\[var\(--any-value\)\] { + padding-top: var(--any-value); + padding-bottom: var(--any-value); + } + .pb-\[var\(--any-value\)\] { + padding-bottom: var(--any-value); + } + .pl-\[var\(--any-value\)\] { + padding-left: var(--any-value); + } + .pr-\[var\(--any-value\)\] { + padding-right: var(--any-value); + } + .pt-\[var\(--any-value\)\] { + padding-top: var(--any-value); + } + .indent-\[var\(--any-value\)\] { + text-indent: var(--any-value); + } + .align-\[var\(--any-value\)\] { + vertical-align: var(--any-value); + } + .font-\[var\(--any-value\)\] { + font-weight: var(--any-value); + } + .leading-\[var\(--any-value\)\] { + line-height: var(--any-value); + } + .tracking-\[var\(--any-value\)\] { + letter-spacing: var(--any-value); + } + .text-\[var\(--any-value\)\] { + color: var(--any-value); + } + .text-opacity-\[var\(--any-value\)\] { + --tw-text-opacity: var(--any-value); + } + .decoration-\[var\(--any-value\)\] { + text-decoration-color: var(--any-value); + } + .underline-offset-\[var\(--any-value\)\] { + text-underline-offset: var(--any-value); + } + .placeholder-\[var\(--any-value\)\]::placeholder { + color: var(--any-value); + } + .placeholder-opacity-\[var\(--any-value\)\]::placeholder { + --tw-placeholder-opacity: var(--any-value); + } + .caret-\[var\(--any-value\)\] { + caret-color: var(--any-value); + } + .accent-\[var\(--any-value\)\] { + accent-color: var(--any-value); + } + .opacity-\[var\(--any-value\)\] { + opacity: var(--any-value); + } + .shadow-\[var\(--any-value\)\] { + --tw-shadow-color: var(--any-value); + --tw-shadow: var(--tw-shadow-colored); + } + .outline-offset-\[var\(--any-value\)\] { + outline-offset: var(--any-value); + } + .outline-\[var\(--any-value\)\] { + outline-color: var(--any-value); + } + .ring-\[var\(--any-value\)\] { + --tw-ring-color: var(--any-value); + } + .ring-opacity-\[var\(--any-value\)\] { + --tw-ring-opacity: var(--any-value); + } + .ring-offset-\[var\(--any-value\)\] { + --tw-ring-offset-color: var(--any-value); + } + .blur-\[var\(--any-value\)\] { + --tw-blur: blur(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .brightness-\[var\(--any-value\)\] { + --tw-brightness: brightness(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .contrast-\[var\(--any-value\)\] { + --tw-contrast: contrast(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .drop-shadow-\[var\(--any-value\)\] { + --tw-drop-shadow: drop-shadow(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .grayscale-\[var\(--any-value\)\] { + --tw-grayscale: grayscale(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .hue-rotate-\[var\(--any-value\)\] { + --tw-hue-rotate: hue-rotate(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .invert-\[var\(--any-value\)\] { + --tw-invert: invert(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .saturate-\[var\(--any-value\)\] { + --tw-saturate: saturate(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .sepia-\[var\(--any-value\)\] { + --tw-sepia: sepia(var(--any-value)); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .backdrop-blur-\[var\(--any-value\)\] { + --tw-backdrop-blur: blur(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-brightness-\[var\(--any-value\)\] { + --tw-backdrop-brightness: brightness(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-contrast-\[var\(--any-value\)\] { + --tw-backdrop-contrast: contrast(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-grayscale-\[var\(--any-value\)\] { + --tw-backdrop-grayscale: grayscale(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-hue-rotate-\[var\(--any-value\)\] { + --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-invert-\[var\(--any-value\)\] { + --tw-backdrop-invert: invert(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-opacity-\[var\(--any-value\)\] { + --tw-backdrop-opacity: opacity(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-saturate-\[var\(--any-value\)\] { + --tw-backdrop-saturate: saturate(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .backdrop-sepia-\[var\(--any-value\)\] { + --tw-backdrop-sepia: sepia(var(--any-value)); + backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); + } + .transition-\[var\(--any-value\)\] { + transition-property: var(--any-value); + transition-duration: 0.15s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + } + .delay-\[var\(--any-value\)\] { + transition-delay: var(--any-value); + } + .duration-\[var\(--any-value\)\] { + transition-duration: var(--any-value); + } + .ease-\[var\(--any-value\)\] { + transition-timing-function: var(--any-value); + } + .will-change-\[var\(--any-value\)\] { + will-change: var(--any-value); + } + .content-\[var\(--any-value\)\] { + --tw-content: var(--any-value); + content: var(--tw-content); + } + `) }) - test.todo('rewrite the any test to be easier to understand or break it up into multiple tests') }) +test.todo('rewrite the any test to be easier to understand or break it up into multiple tests') diff --git a/tests/apply.test.js b/tests/apply.test.js index e4af6ee58..6f3abd2a9 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -1,2473 +1,2100 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - let sharedHtml = html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+let sharedHtml = html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+` + +test('@apply', () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .basic-example { + @apply rounded-md bg-blue-500 px-4 py-2; + } + .class-order { + @apply p-8 px-3 py-7 pt-4 pr-1; + } + .with-additional-properties { + font-weight: 500; + @apply text-right; + } + .variants { + @apply font-semibold hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + } + .only-variants { + @apply hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + } + .apply-group-variant { + @apply group-hover:text-center lg:group-hover:text-left; + } + .apply-dark-variant { + @apply dark:text-center dark:hover:text-right lg:dark:text-left; + } + .apply-custom-utility { + @apply custom-util hover:custom-util lg:custom-util xl:focus:custom-util; + } + .multiple, + .selectors { + @apply rounded-md bg-blue-500 px-4 py-2; + } + .multiple-variants, + .selectors-variants { + @apply hover:text-center active:text-right lg:focus:text-left; + } + .multiple-group, + .selectors-group { + @apply group-hover:text-center lg:group-hover:text-left; + } + .complex-utilities { + @apply ordinal tabular-nums shadow-lg hover:shadow-xl focus:diagonal-fractions; + } + .use-base-only-a { + @apply font-bold; + } + .use-base-only-b { + @apply use-base-only-a font-normal; + } + .use-dependant-only-a { + @apply font-bold; + } + .use-dependant-only-b { + @apply use-dependant-only-a font-normal; + } + .btn { + @apply rounded py-2 px-4 font-bold; + } + .btn-blue { + @apply btn bg-blue-500 text-white hover:bg-blue-700; + } + .recursive-apply-a { + @apply font-black sm:font-thin; + } + .recursive-apply-b { + @apply recursive-apply-a font-semibold md:font-extralight; + } + .recursive-apply-c { + @apply recursive-apply-b font-bold lg:font-light; + } + .use-with-other-properties-base { + color: green; + @apply font-bold; + } + .use-with-other-properties-component { + @apply use-with-other-properties-base; + } + .add-sibling-properties { + padding: 2rem; + @apply px-4 hover:px-2 lg:px-10 xl:focus:px-1; + padding-top: 3px; + @apply use-with-other-properties-base; + } + + h1 { + @apply text-2xl sm:text-3xl lg:text-2xl; + } + h2 { + @apply text-2xl; + @apply lg:text-2xl; + @apply sm:text-2xl; + } + + .important-modifier { + @apply !rounded-md px-4; + } + + .important-modifier-variant { + @apply px-4 hover:!rounded-md; + } + } + + @layer utilities { + .custom-util { + custom: stuff; + } + + .foo { + @apply animate-spin; + } + + .bar { + @apply animate-pulse !important; + } + } ` - test('@apply', () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .basic-example { - @apply rounded-md bg-blue-500 px-4 py-2; - } - .class-order { - @apply p-8 px-3 py-7 pt-4 pr-1; - } - .with-additional-properties { - font-weight: 500; - @apply text-right; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .basic-example { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); + border-radius: 0.375rem; + padding: 0.5rem 1rem; + } + .class-order { + padding: 1rem 0.25rem 1.75rem 0.75rem; + } + .with-additional-properties { + text-align: right; + font-weight: 500; + } + .variants { + font-weight: 600; + } + .variants:hover { + font-weight: 700; + } + .variants:focus { + font-weight: 500; + } + @media (min-width: 1024px) { .variants { - @apply font-semibold hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + font-weight: 300; } + } + @media (min-width: 1280px) { + .variants:focus { + font-weight: 900; + } + } + .only-variants:hover { + font-weight: 700; + } + .only-variants:focus { + font-weight: 500; + } + @media (min-width: 1024px) { .only-variants { - @apply hover:font-bold focus:font-medium lg:font-light xl:focus:font-black; + font-weight: 300; } - .apply-group-variant { - @apply group-hover:text-center lg:group-hover:text-left; + } + @media (min-width: 1280px) { + .only-variants:focus { + font-weight: 900; } - .apply-dark-variant { - @apply dark:text-center dark:hover:text-right lg:dark:text-left; + } + .group:hover .apply-group-variant { + text-align: center; + } + @media (min-width: 1024px) { + .group:hover .apply-group-variant { + text-align: left; } + } + :is(.dark .apply-dark-variant) { + text-align: center; + } + :is(.dark .apply-dark-variant:hover) { + text-align: right; + } + @media (min-width: 1024px) { + :is(.dark .apply-dark-variant) { + text-align: left; + } + } + .apply-custom-utility, + .apply-custom-utility:hover { + custom: stuff; + } + @media (min-width: 1024px) { .apply-custom-utility { - @apply custom-util hover:custom-util lg:custom-util xl:focus:custom-util; - } - .multiple, - .selectors { - @apply rounded-md bg-blue-500 px-4 py-2; - } - .multiple-variants, - .selectors-variants { - @apply hover:text-center active:text-right lg:focus:text-left; - } - .multiple-group, - .selectors-group { - @apply group-hover:text-center lg:group-hover:text-left; - } - .complex-utilities { - @apply ordinal tabular-nums shadow-lg hover:shadow-xl focus:diagonal-fractions; - } - .use-base-only-a { - @apply font-bold; - } - .use-base-only-b { - @apply use-base-only-a font-normal; - } - .use-dependant-only-a { - @apply font-bold; - } - .use-dependant-only-b { - @apply use-dependant-only-a font-normal; - } - .btn { - @apply rounded py-2 px-4 font-bold; - } - .btn-blue { - @apply btn bg-blue-500 text-white hover:bg-blue-700; - } - .recursive-apply-a { - @apply font-black sm:font-thin; - } - .recursive-apply-b { - @apply recursive-apply-a font-semibold md:font-extralight; - } - .recursive-apply-c { - @apply recursive-apply-b font-bold lg:font-light; - } - .use-with-other-properties-base { - color: green; - @apply font-bold; - } - .use-with-other-properties-component { - @apply use-with-other-properties-base; - } - .add-sibling-properties { - padding: 2rem; - @apply px-4 hover:px-2 lg:px-10 xl:focus:px-1; - padding-top: 3px; - @apply use-with-other-properties-base; - } - - h1 { - @apply text-2xl sm:text-3xl lg:text-2xl; - } - h2 { - @apply text-2xl; - @apply lg:text-2xl; - @apply sm:text-2xl; - } - - .important-modifier { - @apply !rounded-md px-4; - } - - .important-modifier-variant { - @apply px-4 hover:!rounded-md; - } - } - - @layer utilities { - .custom-util { custom: stuff; } - - .foo { - @apply animate-spin; - } - - .bar { - @apply animate-pulse !important; - } } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .basic-example { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .class-order { - padding: 1rem 0.25rem 1.75rem 0.75rem; - } - .with-additional-properties { - text-align: right; - font-weight: 500; - } - .variants { - font-weight: 600; - } - .variants:hover { - font-weight: 700; - } - .variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .variants:focus { - font-weight: 900; - } - } - .only-variants:hover { - font-weight: 700; - } - .only-variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .only-variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .only-variants:focus { - font-weight: 900; - } - } - .group:hover .apply-group-variant { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .apply-group-variant { - text-align: left; - } - } - :is(.dark .apply-dark-variant) { - text-align: center; - } - :is(.dark .apply-dark-variant:hover) { - text-align: right; - } - @media (min-width: 1024px) { - :is(.dark .apply-dark-variant) { - text-align: left; - } - } - .apply-custom-utility, - .apply-custom-utility:hover { + @media (min-width: 1280px) { + .apply-custom-utility:focus { custom: stuff; } - @media (min-width: 1024px) { - .apply-custom-utility { - custom: stuff; - } - } - @media (min-width: 1280px) { - .apply-custom-utility:focus { - custom: stuff; - } - } - .multiple, - .selectors { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .multiple-variants:hover, - .selectors-variants:hover { - text-align: center; - } - .multiple-variants:active, - .selectors-variants:active { - text-align: right; - } - @media (min-width: 1024px) { - .multiple-variants:focus, - .selectors-variants:focus { - text-align: left; - } + } + .multiple, + .selectors { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); + border-radius: 0.375rem; + padding: 0.5rem 1rem; + } + .multiple-variants:hover, + .selectors-variants:hover { + text-align: center; + } + .multiple-variants:active, + .selectors-variants:active { + text-align: right; + } + @media (min-width: 1024px) { + .multiple-variants:focus, + .selectors-variants:focus { + text-align: left; } + } + .group:hover .multiple-group, + .group:hover .selectors-group { + text-align: center; + } + @media (min-width: 1024px) { .group:hover .multiple-group, .group:hover .selectors-group { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .multiple-group, - .group:hover .selectors-group { - text-align: left; - } - } - .complex-utilities { - --tw-ordinal: ordinal; - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:hover { - --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), - 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:focus { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .use-base-only-a { - font-weight: 700; - } - .use-dependant-only-b { - font-weight: 400; - } - .btn { - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue:hover { - --tw-bg-opacity: 1; - background-color: rgb(29 78 216 / var(--tw-bg-opacity)); + text-align: left; } + } + .complex-utilities { + --tw-ordinal: ordinal; + --tw-numeric-spacing: tabular-nums; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) + var(--tw-numeric-spacing) var(--tw-numeric-fraction); + --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), + 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .complex-utilities:hover { + --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), + 0 8px 10px -6px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .complex-utilities:focus { + --tw-numeric-fraction: diagonal-fractions; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) + var(--tw-numeric-spacing) var(--tw-numeric-fraction); + } + .use-base-only-a { + font-weight: 700; + } + .use-dependant-only-b { + font-weight: 400; + } + .btn { + border-radius: 0.25rem; + padding: 0.5rem 1rem; + font-weight: 700; + } + .btn-blue { + --tw-bg-opacity: 1; + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + border-radius: 0.25rem; + padding: 0.5rem 1rem; + font-weight: 700; + } + .btn-blue:hover { + --tw-bg-opacity: 1; + background-color: rgb(29 78 216 / var(--tw-bg-opacity)); + } + .recursive-apply-a { + font-weight: 900; + } + @media (min-width: 640px) { .recursive-apply-a { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-a { - font-weight: 100; - } + font-weight: 100; } + } + .recursive-apply-b { + font-weight: 900; + } + @media (min-width: 640px) { .recursive-apply-b { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-b { - font-weight: 100; - } + font-weight: 100; } + } + .recursive-apply-b { + font-weight: 600; + } + @media (min-width: 768px) { .recursive-apply-b { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-b { - font-weight: 200; - } + font-weight: 200; } + } + .recursive-apply-c { + font-weight: 900; + } + @media (min-width: 640px) { .recursive-apply-c { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-c { - font-weight: 100; - } + font-weight: 100; } + } + .recursive-apply-c { + font-weight: 600; + } + @media (min-width: 768px) { .recursive-apply-c { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-c { - font-weight: 200; - } + font-weight: 200; } + } + .recursive-apply-c { + font-weight: 700; + } + @media (min-width: 1024px) { .recursive-apply-c { - font-weight: 700; - } - @media (min-width: 1024px) { - .recursive-apply-c { - font-weight: 300; - } - } - .use-with-other-properties-base, - .use-with-other-properties-component { - color: green; - font-weight: 700; + font-weight: 300; } + } + .use-with-other-properties-base, + .use-with-other-properties-component { + color: green; + font-weight: 700; + } + .add-sibling-properties { + padding: 2rem 1rem; + } + .add-sibling-properties:hover { + padding-left: 0.5rem; + padding-right: 0.5rem; + } + @media (min-width: 1024px) { .add-sibling-properties { - padding: 2rem 1rem; + padding-left: 2.5rem; + padding-right: 2.5rem; } - .add-sibling-properties:hover { - padding-left: 0.5rem; - padding-right: 0.5rem; + } + @media (min-width: 1280px) { + .add-sibling-properties:focus { + padding-left: 0.25rem; + padding-right: 0.25rem; } - @media (min-width: 1024px) { - .add-sibling-properties { - padding-left: 2.5rem; - padding-right: 2.5rem; - } - } - @media (min-width: 1280px) { - .add-sibling-properties:focus { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - } - .add-sibling-properties { - color: green; - padding-top: 3px; - font-weight: 700; + } + .add-sibling-properties { + color: green; + padding-top: 3px; + font-weight: 700; + } + h1 { + font-size: 1.5rem; + line-height: 2rem; + } + @media (min-width: 640px) { + h1 { + font-size: 1.875rem; + line-height: 2.25rem; } + } + @media (min-width: 1024px) { h1 { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 640px) { - h1 { - font-size: 1.875rem; - line-height: 2.25rem; - } - } - @media (min-width: 1024px) { - h1 { - font-size: 1.5rem; - line-height: 2rem; - } - } + } + h2 { + font-size: 1.5rem; + line-height: 2rem; + } + @media (min-width: 1024px) { h2 { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 1024px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - @media (min-width: 640px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - .important-modifier { - padding-left: 1rem; - padding-right: 1rem; - border-radius: 0.375rem !important; - } - .important-modifier-variant { - padding-left: 1rem; - padding-right: 1rem; - } - .important-modifier-variant:hover { - border-radius: 0.375rem !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .foo { - animation: 1s linear infinite spin; - } - @keyframes pulse { - 50% { - opacity: 0.5; - } - } - .bar { - animation: 2s cubic-bezier(0.4, 0, 0.6, 1) infinite pulse !important; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .basic-example { - background-color: #3b82f6; - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .class-order { - padding: 1rem 0.25rem 1.75rem 0.75rem; - } - .with-additional-properties { - text-align: right; - font-weight: 500; - } - .variants { - font-weight: 600; - } - .variants:hover { - font-weight: 700; - } - .variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .variants:focus { - font-weight: 900; - } - } - .only-variants:hover { - font-weight: 700; - } - .only-variants:focus { - font-weight: 500; - } - @media (min-width: 1024px) { - .only-variants { - font-weight: 300; - } - } - @media (min-width: 1280px) { - .only-variants:focus { - font-weight: 900; - } - } - .group:hover .apply-group-variant { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .apply-group-variant { - text-align: left; - } - } - :is(.dark .apply-dark-variant) { - text-align: center; - } - :is(.dark .apply-dark-variant:hover) { - text-align: right; - } - @media (min-width: 1024px) { - :is(.dark .apply-dark-variant) { - text-align: left; - } - } - .apply-custom-utility, - .apply-custom-utility:hover { - custom: stuff; - } - @media (min-width: 1024px) { - .apply-custom-utility { - custom: stuff; - } - } - @media (min-width: 1280px) { - .apply-custom-utility:focus { - custom: stuff; - } - } - .multiple, - .selectors { - background-color: #3b82f6; - border-radius: 0.375rem; - padding: 0.5rem 1rem; - } - .multiple-variants:hover, - .selectors-variants:hover { - text-align: center; - } - .multiple-variants:active, - .selectors-variants:active { - text-align: right; - } - @media (min-width: 1024px) { - .multiple-variants:focus, - .selectors-variants:focus { - text-align: left; - } - } - .group:hover .multiple-group, - .group:hover .selectors-group { - text-align: center; - } - @media (min-width: 1024px) { - .group:hover .multiple-group, - .group:hover .selectors-group { - text-align: left; - } - } - .complex-utilities { - --tw-ordinal: ordinal; - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:hover { - --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), - 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .complex-utilities:focus { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .use-base-only-a { - font-weight: 700; - } - .use-dependant-only-b { - font-weight: 400; - } - .btn { - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue { - color: #fff; - background-color: #3b82f6; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - font-weight: 700; - } - .btn-blue:hover { - background-color: #1d4ed8; - } - .recursive-apply-a { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-a { - font-weight: 100; - } - } - .recursive-apply-b { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-b { - font-weight: 100; - } - } - .recursive-apply-b { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-b { - font-weight: 200; - } - } - .recursive-apply-c { - font-weight: 900; - } - @media (min-width: 640px) { - .recursive-apply-c { - font-weight: 100; - } - } - .recursive-apply-c { - font-weight: 600; - } - @media (min-width: 768px) { - .recursive-apply-c { - font-weight: 200; - } - } - .recursive-apply-c { - font-weight: 700; - } - @media (min-width: 1024px) { - .recursive-apply-c { - font-weight: 300; - } - } - .use-with-other-properties-base, - .use-with-other-properties-component { - color: green; - font-weight: 700; - } - .add-sibling-properties { - padding: 2rem 1rem; - } - .add-sibling-properties:hover { - padding-left: 0.5rem; - padding-right: 0.5rem; - } - @media (min-width: 1024px) { - .add-sibling-properties { - padding-left: 2.5rem; - padding-right: 2.5rem; - } - } - @media (min-width: 1280px) { - .add-sibling-properties:focus { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - } - .add-sibling-properties { - color: green; - padding-top: 3px; - font-weight: 700; - } - h1 { - font-size: 1.5rem; - line-height: 2rem; - } - @media (min-width: 640px) { - h1 { - font-size: 1.875rem; - line-height: 2.25rem; - } - } - @media (min-width: 1024px) { - h1 { - font-size: 1.5rem; - line-height: 2rem; - } - } + } + @media (min-width: 640px) { h2 { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 1024px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - @media (min-width: 640px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - .important-modifier { - padding-left: 1rem; - padding-right: 1rem; - border-radius: 0.375rem !important; - } - .important-modifier-variant { - padding-left: 1rem; - padding-right: 1rem; - } - .important-modifier-variant:hover { - border-radius: 0.375rem !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .foo { - animation: 1s linear infinite spin; - } - @keyframes pulse { - 50% { - opacity: 0.5; - } - } - .bar { - animation: 2s cubic-bezier(0.4, 0, 0.6, 1) infinite pulse !important; - } - `) - }) - }) - - test('@apply error with unknown utility', async () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply a-utility-that-does-not-exist; + } + .important-modifier { + padding-left: 1rem; + padding-right: 1rem; + border-radius: 0.375rem !important; + } + .important-modifier-variant { + padding-left: 1rem; + padding-right: 1rem; + } + .important-modifier-variant:hover { + border-radius: 0.375rem !important; + } + @keyframes spin { + to { + transform: rotate(360deg); } } - ` - - await expect(run(input, config)).rejects.toThrowError('class does not exist') - }) - - test('@apply error with nested @screen', async () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @screen md { - @apply text-black; - } - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - '@apply is not supported within nested at-rules like @screen' - ) - }) - - test('@apply error with nested @anyatrulehere', async () => { - let config = { - darkMode: 'class', - content: [{ raw: sharedHtml }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @genie { - @apply text-black; - } - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - '@apply is not supported within nested at-rules like @genie' - ) - }) - - test('@apply error when using .group utility', async () => { - let config = { - darkMode: 'class', - content: [{ raw: '
' }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply group; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'group' utility` - ) - }) - - test('@apply error when using a prefixed .group utility', async () => { - let config = { - prefix: 'tw-', - darkMode: 'class', - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply tw-group; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'tw-group' utility` - ) - }) - - test('@apply error when using .peer utility', async () => { - let config = { - darkMode: 'class', - content: [{ raw: '
' }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply peer; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'peer' utility` - ) - }) - - test('@apply error when using a prefixed .peer utility', async () => { - let config = { - prefix: 'tw-', - darkMode: 'class', - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - @apply tw-peer; - } - } - ` - - await expect(run(input, config)).rejects.toThrowError( - `@apply should not be used with the 'tw-peer' utility` - ) - }) - - test('@apply classes from outside a @layer', async () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind components; - @tailwind utilities; - .foo { - @apply font-bold; + animation: 1s linear infinite spin; + } + @keyframes pulse { + 50% { + opacity: 0.5; + } } - .bar { - @apply foo text-red-500 hover:text-green-500; + animation: 2s cubic-bezier(0.4, 0, 0.6, 1) infinite pulse !important; } + `) + }) +}) +test('@apply error with unknown utility', async () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply a-utility-that-does-not-exist; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError('class does not exist') +}) + +test('@apply error with nested @screen', async () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @screen md { + @apply text-black; + } + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + '@apply is not supported within nested at-rules like @screen' + ) +}) + +test('@apply error with nested @anyatrulehere', async () => { + let config = { + darkMode: 'class', + content: [{ raw: sharedHtml }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @genie { + @apply text-black; + } + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + '@apply is not supported within nested at-rules like @genie' + ) +}) + +test('@apply error when using .group utility', async () => { + let config = { + darkMode: 'class', + content: [{ raw: '
' }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply group; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'group' utility` + ) +}) + +test('@apply error when using a prefixed .group utility', async () => { + let config = { + prefix: 'tw-', + darkMode: 'class', + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply tw-group; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'tw-group' utility` + ) +}) + +test('@apply error when using .peer utility', async () => { + let config = { + darkMode: 'class', + content: [{ raw: '
' }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply peer; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'peer' utility` + ) +}) + +test('@apply error when using a prefixed .peer utility', async () => { + let config = { + prefix: 'tw-', + darkMode: 'class', + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + @apply tw-peer; + } + } + ` + + await expect(run(input, config)).rejects.toThrowError( + `@apply should not be used with the 'tw-peer' utility` + ) +}) + +test('@apply classes from outside a @layer', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + @apply font-bold; + } + + .bar { + @apply foo text-red-500 hover:text-green-500; + } + + .baz { + @apply bar underline; + } + + .keep-me-even-though-I-am-not-used-in-content { + color: green; + } + ` + + await run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold, + .foo { + font-weight: 700; + } + .bar { + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); + font-weight: 700; + } + .bar:hover { + --tw-text-opacity: 1; + color: rgb(34 197 94 / var(--tw-text-opacity)); + } .baz { - @apply bar underline; + --tw-text-opacity: 1; + color: rgb(239 68 68 / var(--tw-text-opacity)); + font-weight: 700; + text-decoration-line: underline; + } + .baz:hover { + --tw-text-opacity: 1; + color: rgb(34 197 94 / var(--tw-text-opacity)); } - .keep-me-even-though-I-am-not-used-in-content { color: green; } - ` - - await run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .font-bold, - .foo { - font-weight: 700; - } - .bar { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - font-weight: 700; - } - .bar:hover { - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - } - .baz { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - font-weight: 700; - text-decoration-line: underline; - } - .baz:hover { - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - } - .keep-me-even-though-I-am-not-used-in-content { - color: green; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .font-bold, - .foo { - font-weight: 700; - } - .bar { - color: #ef4444; - font-weight: 700; - } - .bar:hover { - color: #22c55e; - } - .baz { - color: #ef4444; - font-weight: 700; - text-decoration-line: underline; - } - .baz:hover { - color: #22c55e; - } - .keep-me-even-though-I-am-not-used-in-content { - color: green; - } - `) - }) + `) }) +}) - test('@applying classes from outside a @layer respects the source order', async () => { - let config = { - content: [{ raw: html`
` }], +test('@applying classes from outside a @layer respects the source order', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + .baz { + @apply bar underline; } - let input = css` + @tailwind components; + + .keep-me-even-though-I-am-not-used-in-content { + color: green; + } + + @tailwind utilities; + + .foo { + @apply font-bold; + } + + .bar { + @apply no-underline; + } + ` + + await run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` .baz { - @apply bar underline; + text-decoration-line: none; } - - @tailwind components; - - .keep-me-even-though-I-am-not-used-in-content { - color: green; + .container { + width: 100%; } - - @tailwind utilities; - - .foo { - @apply font-bold; - } - - .bar { - @apply no-underline; - } - ` - - await run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .baz { - text-decoration-line: none; - } + @media (min-width: 640px) { .container { - width: 100%; + max-width: 640px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } + } + @media (min-width: 768px) { + .container { + max-width: 768px; } - @media (min-width: 768px) { - .container { - max-width: 768px; - } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .keep-me-even-though-I-am-not-used-in-content { - color: green; - } - .font-bold, - .foo { - font-weight: 700; - } - .bar { - text-decoration-line: none; - } - `) - }) - }) - - it('should remove duplicate properties when using apply with similar properties', () => { - let config = { - content: [{ raw: 'foo' }], - } - - let input = css` - @tailwind utilities; - + } + .keep-me-even-though-I-am-not-used-in-content { + color: green; + } + .font-bold, .foo { - @apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform; + font-weight: 700; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - --tw-translate-x: -50%; - --tw-translate-y: -50%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - position: absolute; - top: 50%; - left: 50%; - } - `) - }) + .bar { + text-decoration-line: none; + } + `) }) +}) - it('should apply all the definitions of a class', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], +it('should remove duplicate properties when using apply with similar properties', () => { + let config = { + content: [{ raw: 'foo' }], + } + + let input = css` + @tailwind utilities; + + .foo { + @apply absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transform; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + --tw-translate-x: -50%; + --tw-translate-y: -50%; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + position: absolute; + top: 50%; + left: 50%; + } + `) + }) +}) + +it('should apply all the definitions of a class', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer utilities { + .aspect-w-1 { + position: relative; + } + + .aspect-w-1 { + --tw-aspect-w: 1; + } } - let input = css` - @tailwind components; - @tailwind utilities; - - @layer utilities { - .aspect-w-1 { - position: relative; - } - - .aspect-w-1 { - --tw-aspect-w: 1; - } + @layer components { + .foo { + @apply aspect-w-1; } - - @layer components { - .foo { - @apply aspect-w-1; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .foo { - --tw-aspect-w: 1; - position: relative; - } - `) - }) - }) - - it('should throw when trying to apply a direct circular dependency', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], } + ` - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo:not(.text-red-500) { - @apply text-red-500; - } + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo { + --tw-aspect-w: 1; + position: relative; } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `text-red-500` utility here because it creates a circular dependency.' - ) - }) + `) }) +}) - it('should throw when trying to apply an indirect circular dependency', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } +it('should throw when trying to apply a direct circular dependency', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; + let input = css` + @tailwind components; + @tailwind utilities; - @layer components { - .a { - @apply b; - } - - .b { - @apply c; - } - - .c { - @apply a; - } + @layer components { + .foo:not(.text-red-500) { + @apply text-red-500; } - ` + } + ` - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' - ) - }) + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `text-red-500` utility here because it creates a circular dependency.' + ) }) +}) - it('should not throw when the selector is different (but contains the base partially)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } +it('should throw when trying to apply an indirect circular dependency', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; + let input = css` + @tailwind components; + @tailwind utilities; - .focus\:bg-gray-500 { - @apply bg-gray-500; - } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-gray-500, - .focus\:bg-gray-500 { - --tw-bg-opacity: 1; - background-color: rgb(107 114 128 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-gray-500, - .focus\:bg-gray-500 { - background-color: #6b7280; - } - `) - }) - }) - - it('should throw when trying to apply an indirect circular dependency with a modifier (1)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .a { - @apply b; - } - - .b { - @apply c; - } - - .c { - @apply hover:a; - } - } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `hover:a` utility here because it creates a circular dependency.' - ) - }) - }) - - it('should throw when trying to apply an indirect circular dependency with a modifier (2)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .a { - @apply b; - } - - .b { - @apply hover:c; - } - - .c { - @apply a; - } - } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' - ) - }) - }) - - it('should not throw when the circular dependency is part of a different selector (1)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - html.dark .a, - .b { - color: red; - } - } - - html.dark .c { + @layer components { + .a { @apply b; } - ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - html.dark .c { - color: red; - } - `) - }) - }) + .b { + @apply c; + } - it('should not throw when the circular dependency is part of a different selector (2)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + .c { + @apply a; + } } + ` - let input = css` - @tailwind utilities; - - @layer utilities { - html.dark .a, - .b { - color: red; - } - } - - html.dark .c { - @apply hover:b; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - html.dark .c:hover { - color: red; - } - `) - }) + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' + ) }) +}) - it('should throw when the circular dependency is part of the same selector', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], +it('should not throw when the selector is different (but contains the base partially)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .focus\:bg-gray-500 { + @apply bg-gray-500; } + ` - let input = css` - @tailwind utilities; - - @layer utilities { - html.dark .a, - html.dark .b { - color: red; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-gray-500, + .focus\:bg-gray-500 { + --tw-bg-opacity: 1; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)); } - - html.dark .c { - @apply hover:b; - } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'You cannot `@apply` the `hover:b` utility here because it creates a circular dependency.' - ) - }) + `) }) +}) - it('rules with vendor prefixes are still separate when optimizing defaults rules', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should throw when trying to apply an indirect circular dependency with a modifier (1)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; + let input = css` + @tailwind components; + @tailwind utilities; - @layer components { - input[type='range']::-moz-range-thumb { - @apply border; - } + @layer components { + .a { + @apply b; } - ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - input[type='range']::-moz-range-thumb { - border-width: 1px; - } - .border { - border-width: 1px; - } - `) - }) - }) + .b { + @apply c; + } - it('should be possible to apply user css', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + .c { + @apply hover:a; + } } + ` - let input = css` - @tailwind components; - @tailwind utilities; + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `hover:a` utility here because it creates a circular dependency.' + ) + }) +}) - .foo { +it('should throw when trying to apply an indirect circular dependency with a modifier (2)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .a { + @apply b; + } + + .b { + @apply hover:c; + } + + .c { + @apply a; + } + } + ` + + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `a` utility here because it creates a circular dependency.' + ) + }) +}) + +it('should not throw when the circular dependency is part of a different selector (1)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + html.dark .a, + .b { color: red; } + } + + html.dark .c { + @apply b; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + html.dark .c { + color: red; + } + `) + }) +}) + +it('should not throw when the circular dependency is part of a different selector (2)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + html.dark .a, + .b { + color: red; + } + } + + html.dark .c { + @apply hover:b; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + html.dark .c:hover { + color: red; + } + `) + }) +}) + +it('should throw when the circular dependency is part of the same selector', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + html.dark .a, + html.dark .b { + color: red; + } + } + + html.dark .c { + @apply hover:b; + } + ` + + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'You cannot `@apply` the `hover:b` utility here because it creates a circular dependency.' + ) + }) +}) + +it('rules with vendor prefixes are still separate when optimizing defaults rules', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer components { + input[type='range']::-moz-range-thumb { + @apply border; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + input[type='range']::-moz-range-thumb { + border-width: 1px; + } + .border { + border-width: 1px; + } + `) + }) +}) + +it('should be possible to apply user css', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + color: red; + } + + .bar { + @apply foo; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo, + .bar { + color: red; + } + `) + }) +}) + +it('should not be possible to apply user css with variants', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + color: red; + } + + .bar { + @apply hover:foo; + } + ` + + return run(input, config).catch((err) => { + expect(err.reason).toBe( + 'The `hover:foo` class does not exist. If `hover:foo` is a custom class, make sure it is defined within a `@layer` directive.' + ) + }) +}) + +it('should not apply unrelated siblings when applying something from within atrules', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .foo { + font-weight: bold; + @apply bar; + } .bar { - @apply foo; + color: green; } - ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .foo, + @supports (a: b) { .bar { + color: blue; + } + + .something-unrelated { color: red; } - `) - }) - }) - - it('should not be possible to apply user css with variants', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + } } + ` - let input = css` - @tailwind components; - @tailwind utilities; - + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` .foo { - color: red; + color: green; + font-weight: bold; + } + @supports (a: b) { + .foo { + color: #00f; + } } - .bar { - @apply hover:foo; + color: green; } - ` - - return run(input, config).catch((err) => { - expect(err.reason).toBe( - 'The `hover:foo` class does not exist. If `hover:foo` is a custom class, make sure it is defined within a `@layer` directive.' - ) - }) - }) - - it('should not apply unrelated siblings when applying something from within atrules', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .foo { - font-weight: bold; - @apply bar; - } - + @supports (a: b) { .bar { - color: green; + color: #00f; } - - @supports (a: b) { - .bar { - color: blue; - } - - .something-unrelated { - color: red; - } + .something-unrelated { + color: red; } } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - color: green; - font-weight: bold; - } - @supports (a: b) { - .foo { - color: #00f; - } - } - .bar { - color: green; - } - @supports (a: b) { - .bar { - color: #00f; - } - .something-unrelated { - color: red; - } - } - `) - }) + `) }) +}) - it('should be possible to apply user css without tailwind directives', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], +it('should be possible to apply user css without tailwind directives', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .bop { + color: red; } + .bar { + background-color: blue; + } + .foo { + @apply bar bop absolute; + } + ` - let input = css` + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` .bop { color: red; } .bar { - background-color: blue; + background-color: #00f; } .foo { - @apply bar bop absolute; + color: red; + background-color: #00f; + position: absolute; + } + `) + }) +}) + +it('should be possible to apply a class from another rule with multiple selectors (2 classes)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { + .a, + .b { + @apply underline; + } + + .c { + @apply b; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .c { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 tag)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + span, + .b { + @apply underline; + } + + .c { + @apply b; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + span, + .b, + .c { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 id)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { + #a, + .b { + @apply underline; + } + + .c { + @apply b; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + #a, + .b, + .c { + text-decoration-line: underline; + } + `) + }) +}) + +describe('multiple instances', () => { + it('should be possible to apply multiple "instances" of the same class', () => { + let config = { + content: [{ raw: html`` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + .a { + @apply b; + } + + .b { + @apply uppercase; + } + + .b { + color: red; } ` return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - .bop { - color: red; - } - .bar { - background-color: #00f; - } - .foo { - color: red; - background-color: #00f; - position: absolute; - } - `) - }) - }) - - it('should be possible to apply a class from another rule with multiple selectors (2 classes)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - @layer utilities { .a, .b { - @apply underline; - } - - .c { - @apply b; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .c { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 tag)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - span, - .b { - @apply underline; - } - - .c { - @apply b; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - span, - .b, - .c { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to apply a class from another rule with multiple selectors (1 class, 1 id)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - @layer utilities { - #a, - .b { - @apply underline; - } - - .c { - @apply b; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - #a, - .b, - .c { - text-decoration-line: underline; - } - `) - }) - }) - - describe('multiple instances', () => { - it('should be possible to apply multiple "instances" of the same class', () => { - let config = { - content: [{ raw: html`` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - .a { - @apply b; - } - - .b { - @apply uppercase; - } - - .b { + text-transform: uppercase; color: red; } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .a, - .b { - text-transform: uppercase; - color: red; - } - `) - }) - }) - - it('should be possible to apply a combination of multiple "instances" of the same class', () => { - let config = { - content: [{ raw: html`` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - .a { - @apply b; - } - - .b { - @apply uppercase; - color: red; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .a, - .b { - text-transform: uppercase; - color: red; - } - `) - }) - }) - - it('should generate the same output, even if it was used in a @layer', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind components; - - @layer components { - .a { - @apply b; - } - - .b { - @apply uppercase; - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .a, - .b { - text-transform: uppercase; - color: red; - } - `) - }) - }) - - it('should be possible to apply a combination of multiple "instances" of the same class (defined in a layer)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind components; - - @layer components { - .a { - color: red; - @apply b; - color: blue; - } - - .b { - @apply text-green-500; - text-decoration: underline; - } - } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .a { - color: red; - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - color: #00f; - text-decoration: underline; - } - .b { - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); - text-decoration: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .a { - color: red; - color: #22c55e; - color: #00f; - text-decoration: underline; - } - .b { - color: #22c55e; - text-decoration: underline; - } - `) - }) - }) - - it('should properly maintain the order', () => { - let config = { - content: [{ raw: html`` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - h2 { - @apply text-xl; - @apply lg:text-3xl; - @apply sm:text-2xl; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - h2 { - font-size: 1.25rem; - line-height: 1.75rem; - } - @media (min-width: 1024px) { - h2 { - font-size: 1.875rem; - line-height: 2.25rem; - } - } - @media (min-width: 640px) { - h2 { - font-size: 1.5rem; - line-height: 2rem; - } - } - `) - }) - }) - }) - - it('apply can emit defaults in isolated environments without @tailwind directives', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - - content: [{ raw: html`
` }], - } - - let input = css` - .foo { - @apply focus:rotate-90; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .foo:focus { - --tw-rotate: 90deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } `) }) }) - it('apply does not emit defaults in isolated environments without optimizeUniversalDefaults', () => { + it('should be possible to apply a combination of multiple "instances" of the same class', () => { let config = { - experimental: { optimizeUniversalDefaults: false }, - content: [{ raw: html`
` }], + content: [{ raw: html`` }], + plugins: [], corePlugins: { preflight: false }, } let input = css` - @tailwind base; + .a { + @apply b; + } - .foo { - @apply focus:rotate-90; + .b { + @apply uppercase; + color: red; } ` return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .foo:focus { - --tw-rotate: 90deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + .a, + .b { + text-transform: uppercase; + color: red; } `) }) }) - it('should work outside of layer', async () => { + it('should generate the same output, even if it was used in a @layer', () => { let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - .input-text { - @apply bg-white; - background-color: red; - } - ` - - let result - result = await run(input, config) - - stable.expect(result.css).toMatchFormattedCss(css` - .input-text { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - background-color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .input-text { - background-color: red; - } - `) - - result = await run(input, config) - - stable.expect(result.css).toMatchFormattedCss(css` - .input-text { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - background-color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .input-text { - background-color: red; - } - `) - }) - - it('should work in layer', async () => { - let config = { - content: [{ raw: html`
` }], + content: [{ raw: html`
` }], + plugins: [], corePlugins: { preflight: false }, } let input = css` @tailwind components; + @layer components { - .input-text { - @apply bg-white; - background-color: red; + .a { + @apply b; + } + + .b { + @apply uppercase; + color: red; } } ` - await run(input, config) - const result = await run(input, config) - - stable.expect(result.css).toMatchFormattedCss(css` - .input-text { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - background-color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .input-text { - background-color: red; - } - `) + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .a, + .b { + text-transform: uppercase; + color: red; + } + `) + }) }) - it('apply partitioning works with media queries', async () => { + it('should be possible to apply a combination of multiple "instances" of the same class (defined in a layer)', () => { let config = { - content: [{ raw: html`` }], + content: [{ raw: html`
` }], + plugins: [], corePlugins: { preflight: false }, } let input = css` - @tailwind base; - @layer base { - html, - body { - @apply text-green-600; - font-size: 1rem; + @tailwind components; + + @layer components { + .a { + color: red; + @apply b; + color: blue; } - @media print { - html, - body { - @apply text-red-600; - font-size: 2rem; - } + .b { + @apply text-green-500; + text-decoration: underline; } } ` - await run(input, config) - const result = await run(input, config) - - stable.expect(result.css).toMatchFormattedCss(css` - html, - body { - --tw-text-opacity: 1; - color: rgb(22 163 74 / var(--tw-text-opacity)); - font-size: 1rem; - } - @media print { - html, - body { - --tw-text-opacity: 1; - color: rgb(220 38 38 / var(--tw-text-opacity)); - font-size: 2rem; - } - } - ${defaults} - `) - oxide.expect(result.css).toMatchFormattedCss(css` - html, - body { - color: #16a34a; - font-size: 1rem; - } - @media print { - html, - body { - color: #dc2626; - font-size: 2rem; - } - } - ${defaults} - `) - }) - - it('should be possible to use apply in plugins', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents }) { - addComponents({ - '.a': { - color: 'red', - }, - '.b': { - '@apply a': {}, - color: 'blue', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .a { color: red; + --tw-text-opacity: 1; + color: rgb(34 197 94 / var(--tw-text-opacity)); + color: #00f; + text-decoration: underline; } .b { - color: red; - color: #00f; + --tw-text-opacity: 1; + color: rgb(34 197 94 / var(--tw-text-opacity)); + text-decoration: underline; } `) }) }) - it('should apply using the updated user CSS when the source has changed', async () => { + it('should properly maintain the order', () => { let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let inputBefore = css` - .foo { - color: green; - } - - .bar { - @apply foo; - } - ` - - let inputAfter = css` - .foo { - color: red; - } - - .bar { - @apply foo; - } - ` - - let result = await run(inputBefore, config) - - expect(result.css).toMatchFormattedCss(css` - .foo, - .bar { - color: green; - } - `) - - result = await run(inputAfter, config) - - expect(result.css).toMatchFormattedCss(css` - .foo, - .bar { - color: red; - } - `) - }) - - it('apply + layer utilities + selector variants (like group) + important selector', async () => { - let config = { - important: '#myselector', - content: [{ raw: html`
` }], + content: [{ raw: html`` }], plugins: [], + corePlugins: { preflight: false }, } let input = css` - @tailwind utilities; - @layer utilities { - .custom-utility { - @apply font-normal group-hover:underline; + h2 { + @apply text-xl; + @apply lg:text-3xl; + @apply sm:text-2xl; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + h2 { + font-size: 1.25rem; + line-height: 1.75rem; + } + @media (min-width: 1024px) { + h2 { + font-size: 1.875rem; + line-height: 2.25rem; + } + } + @media (min-width: 640px) { + h2 { + font-size: 1.5rem; + line-height: 2rem; + } + } + `) + }) + }) +}) + +it('apply can emit defaults in isolated environments without @tailwind directives', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + + content: [{ raw: html`
` }], + } + + let input = css` + .foo { + @apply focus:rotate-90; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo:focus { + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +it('apply does not emit defaults in isolated environments without optimizeUniversalDefaults', () => { + let config = { + experimental: { optimizeUniversalDefaults: false }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + + .foo { + @apply focus:rotate-90; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .foo:focus { + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +it('should work outside of layer', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + .input-text { + @apply bg-white; + background-color: red; + } + ` + + let result + result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .input-text { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + background-color: red; + } + `) + + result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .input-text { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + background-color: red; + } + `) +}) + +it('should work in layer', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind components; + @layer components { + .input-text { + @apply bg-white; + background-color: red; + } + } + ` + + await run(input, config) + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .input-text { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + background-color: red; + } + `) +}) + +it('apply partitioning works with media queries', async () => { + let config = { + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @layer base { + html, + body { + @apply text-green-600; + font-size: 1rem; + } + + @media print { + html, + body { + @apply text-red-600; + font-size: 2rem; } } - ` + } + ` - let result = await run(input, config) + await run(input, config) + const result = await run(input, config) - expect(result.css).toMatchFormattedCss(css` - #myselector :is(.custom-utility) { - font-weight: 400; + expect(result.css).toMatchFormattedCss(css` + html, + body { + --tw-text-opacity: 1; + color: rgb(22 163 74 / var(--tw-text-opacity)); + font-size: 1rem; + } + @media print { + html, + body { + --tw-text-opacity: 1; + color: rgb(220 38 38 / var(--tw-text-opacity)); + font-size: 2rem; } - #myselector :is(.group:hover .custom-utility) { - text-decoration-line: underline; + } + ${defaults} + `) +}) + +it('should be possible to use apply in plugins', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents }) { + addComponents({ + '.a': { + color: 'red', + }, + '.b': { + '@apply a': {}, + color: 'blue', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .a { + color: red; + } + .b { + color: red; + color: #00f; } `) }) +}) - it('apply + user CSS + selector variants (like group) + important selector (1)', async () => { - let config = { - important: '#myselector', - content: [{ raw: html`
` }], - plugins: [], +it('should apply using the updated user CSS when the source has changed', async () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let inputBefore = css` + .foo { + color: green; } - let input = css` + .bar { + @apply foo; + } + ` + + let inputAfter = css` + .foo { + color: red; + } + + .bar { + @apply foo; + } + ` + + let result = await run(inputBefore, config) + + expect(result.css).toMatchFormattedCss(css` + .foo, + .bar { + color: green; + } + `) + + result = await run(inputAfter, config) + + expect(result.css).toMatchFormattedCss(css` + .foo, + .bar { + color: red; + } + `) +}) + +it('apply + layer utilities + selector variants (like group) + important selector', async () => { + let config = { + important: '#myselector', + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { .custom-utility { @apply font-normal group-hover:underline; } - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .custom-utility { - font-weight: 400; - } - .group:hover .custom-utility { - text-decoration-line: underline; - } - `) - }) - - it('apply + user CSS + selector variants (like group) + important selector (2)', async () => { - let config = { - important: '#myselector', - content: [{ raw: html`
` }], - plugins: [], } + ` - let input = css` - #myselector .custom-utility { - @apply font-normal group-hover:underline; - } - ` + let result = await run(input, config) - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - #myselector .custom-utility { - font-weight: 400; - } - .group:hover #myselector .custom-utility { - text-decoration-line: underline; - } - `) - }) - - it('can apply user utilities that start with a dash', async () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + expect(result.css).toMatchFormattedCss(css` + #myselector :is(.custom-utility) { + font-weight: 400; } + #myselector :is(.group:hover .custom-utility) { + text-decoration-line: underline; + } + `) +}) - let input = css` - @tailwind utilities; - @layer utilities { - .foo-1 { - margin: 10px; - } - .-foo-1 { - margin: -15px; - } - .new-class { - @apply -foo-1; - } - } - ` +it('apply + user CSS + selector variants (like group) + important selector (1)', async () => { + let config = { + important: '#myselector', + content: [{ raw: html`
` }], + plugins: [], + } - let result = await run(input, config) + let input = css` + .custom-utility { + @apply font-normal group-hover:underline; + } + ` - expect(result.css).toMatchFormattedCss(css` + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .custom-utility { + font-weight: 400; + } + .group:hover .custom-utility { + text-decoration-line: underline; + } + `) +}) + +it('apply + user CSS + selector variants (like group) + important selector (2)', async () => { + let config = { + important: '#myselector', + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + #myselector .custom-utility { + @apply font-normal group-hover:underline; + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + #myselector .custom-utility { + font-weight: 400; + } + .group:hover #myselector .custom-utility { + text-decoration-line: underline; + } + `) +}) + +it('can apply user utilities that start with a dash', async () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + @layer utilities { .foo-1 { margin: 10px; } - .-foo-1, - .new-class { + .-foo-1 { margin: -15px; } - `) - }) + .new-class { + @apply -foo-1; + } + } + ` - it('can apply joined classes when using elements', async () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo-1 { + margin: 10px; + } + .-foo-1, + .new-class { + margin: -15px; + } + `) +}) + +it('can apply joined classes when using elements', async () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .foo.bar { + color: red; + } + .bar.foo { + color: green; + } + header:nth-of-type(odd) { + @apply foo; + } + header::after { + @apply foo; + } + main { + @apply foo bar; + } + footer { + @apply bar; + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo.bar { + color: red; + } + .bar.foo { + color: green; + } + header:nth-of-type(2n + 1).bar { + color: red; + } + header.bar:nth-of-type(2n + 1) { + color: green; + } + header.bar:after, + main.bar, + main.foo, + footer.foo { + color: red; + color: green; + } + `) +}) + +it('should not replace multiple instances of the same class in a single selector', async () => { + // NOTE: This test is non-normative and is not part of the spec of how `@apply` works per-se + // It describes how it currently works because the "correct" way produces a combinatorial explosion + // of selectors that is not easily doable + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + .foo + .foo { + color: blue; + } + .bar + .bar { + color: fuchsia; + } + header { + @apply foo; + } + main { + @apply foo bar; + } + footer { + @apply bar; + } + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo + .foo { + color: #00f; + } + .bar + .bar { + color: #f0f; + } + header + .foo, + main + .foo { + color: #00f; + } + main + .bar, + footer + .bar { + color: #f0f; + } + `) +}) + +it('should maintain the correct selector when applying other utilities', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + } + + let input = css` + @tailwind utilities; + + .foo:hover.bar .baz { + @apply bg-black; + color: red; } - let input = css` - .foo.bar { - color: red; - } - .bar.foo { - color: green; - } - header:nth-of-type(odd) { - @apply foo; - } - header::after { - @apply foo; - } - main { - @apply foo bar; - } - footer { - @apply bar; - } - ` - - let result = await run(input, config) + .foo:hover.bar > .baz { + @apply bg-black; + color: red; + } + ` + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .foo.bar { - color: red; - } - .bar.foo { - color: green; - } - header:nth-of-type(2n + 1).bar { - color: red; - } - header.bar:nth-of-type(2n + 1) { - color: green; - } - header.bar:after, - main.bar, - main.foo, - footer.foo { - color: red; - color: green; - } - `) - }) - - it('should not replace multiple instances of the same class in a single selector', async () => { - // NOTE: This test is non-normative and is not part of the spec of how `@apply` works per-se - // It describes how it currently works because the "correct" way produces a combinatorial explosion - // of selectors that is not easily doable - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - .foo + .foo { - color: blue; - } - .bar + .bar { - color: fuchsia; - } - header { - @apply foo; - } - main { - @apply foo bar; - } - footer { - @apply bar; - } - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .foo + .foo { - color: #00f; - } - .bar + .bar { - color: #f0f; - } - header + .foo, - main + .foo { - color: #00f; - } - main + .bar, - footer + .bar { - color: #f0f; - } - `) - }) - - it('should maintain the correct selector when applying other utilities', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - } - - let input = css` - @tailwind utilities; - - .foo:hover.bar .baz { - @apply bg-black; - color: red; - } - + .foo:hover.bar .baz, .foo:hover.bar > .baz { - @apply bg-black; + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); color: red; } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .foo:hover.bar .baz, - .foo:hover.bar > .baz { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - color: red; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .foo:hover.bar .baz, - .foo:hover.bar > .baz { - color: red; - background-color: #000; - } - `) - }) + `) }) +}) - it('pseudo elements inside apply are moved outside of :is() or :has()', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], +it('pseudo elements inside apply are moved outside of :is() or :has()', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + .foo::before { + @apply dark:bg-black/100; } - let input = css` - .foo::before { - @apply dark:bg-black/100; - } - - .bar::before { - @apply rtl:dark:bg-black/100; - } - - .baz::before { - @apply rtl:dark:hover:bg-black/100; - } - - .qux::file-selector-button { - @apply rtl:dark:hover:bg-black/100; - } - - .steve::before { - @apply rtl:hover:dark:bg-black/100; - } - - .bob::file-selector-button { - @apply rtl:hover:dark:bg-black/100; - } - - .foo::before { - @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; - } - - .bar::file-selector-button { - @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - :is(.dark .foo)::before, - :is([dir='rtl'] :is(.dark .bar))::before, - :is([dir='rtl'] :is(.dark .baz:hover))::before { - background-color: #000; - } - :is([dir='rtl'] :is(.dark .qux))::file-selector-button:hover { - background-color: #000; - } - :is([dir='rtl'] :is(.dark .steve):hover):before { - background-color: #000; - } - :is([dir='rtl'] :is(.dark .bob))::file-selector-button:hover { - background-color: #000; - } - :has([dir='rtl'] .foo:hover):before { - background-color: #000; - } - :has([dir='rtl'] .bar)::file-selector-button:hover { - background-color: #000; - } - `) - }) - }) - - stable.test('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], + .bar::before { + @apply rtl:dark:bg-black/100; } - let input = css` + .baz::before { + @apply rtl:dark:hover:bg-black/100; + } + + .qux::file-selector-button { + @apply rtl:dark:hover:bg-black/100; + } + + .steve::before { + @apply rtl:hover:dark:bg-black/100; + } + + .bob::file-selector-button { + @apply rtl:hover:dark:bg-black/100; + } + + .foo::before { + @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; + } + + .bar::file-selector-button { + @apply [:has([dir="rtl"]_&)]:hover:bg-black/100; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + :is(.dark .foo)::before, + :is([dir='rtl'] :is(.dark .bar))::before, + :is([dir='rtl'] :is(.dark .baz:hover))::before { + background-color: #000; + } + :is([dir='rtl'] :is(.dark .qux))::file-selector-button:hover { + background-color: #000; + } + :is([dir='rtl'] :is(.dark .steve):hover):before { + background-color: #000; + } + :is([dir='rtl'] :is(.dark .bob))::file-selector-button:hover { + background-color: #000; + } + :has([dir='rtl'] .foo:hover):before { + background-color: #000; + } + :has([dir='rtl'] .bar)::file-selector-button:hover { + background-color: #000; + } + `) + }) +}) + +test.skip('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + ::ng-deep .foo .bar { + @apply font-bold; + } + ::v-deep .foo .bar { + @apply font-bold; + } + ::deep .foo .bar { + @apply font-bold; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` ::ng-deep .foo .bar { - @apply font-bold; + font-weight: 700; } ::v-deep .foo .bar { - @apply font-bold; + font-weight: 700; } ::deep .foo .bar { - @apply font-bold; + font-weight: 700; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ::ng-deep .foo .bar { - font-weight: 700; - } - ::v-deep .foo .bar { - font-weight: 700; - } - ::deep .foo .bar { - font-weight: 700; - } - `) - }) + `) }) - - // 1. `::ng-deep` is deprecated - // 2. `::deep` and `::v-deep` are non-standard - // 3. They all use invalid selector syntax that Lightning CSS does not support - // It may be enough for Oxide to not support it at all - oxide.test.todo('::ng-deep, ::deep, ::v-deep pseudo elements are left alone') }) + +// TODO: Oxide +// 1. `::ng-deep` is deprecated +// 2. `::deep` and `::v-deep` are non-standard +// 3. They all use invalid selector syntax that Lightning CSS does not support +// It may be enough for Oxide to not support it at all +test.todo('::ng-deep, ::deep, ::v-deep pseudo elements are left alone') diff --git a/tests/arbitrary-properties.test.js b/tests/arbitrary-properties.test.js index ce52c1bc7..17f0bcf1f 100644 --- a/tests/arbitrary-properties.test.js +++ b/tests/arbitrary-properties.test.js @@ -1,460 +1,456 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('basic arbitrary properties', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('basic arbitrary properties', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[paint-order\:markers\] { - paint-order: markers; - } - `) - }) - }) - - test('different arbitrary properties are picked up separately', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[bar\:baz\] { - bar: baz; - } - .\[foo\:bar\] { - foo: bar; - } - `) - }) - }) - - test('arbitrary properties with modifiers', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - @media (min-width: 1024px) { - .dark\:lg\:hover\:\[paint-order\:markers\]:hover { - paint-order: markers; - } - } - } - `) - }) - }) - - test('arbitrary properties are sorted after utilities', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .content-none { - --tw-content: none; - content: var(--tw-content); - } - .\[paint-order\:markers\] { - paint-order: markers; - } - .hover\:pointer-events-none:hover { - pointer-events: none; - } - `) - }) - }) - - test('using CSS variables', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--my-var\:auto\] { - --my-var: auto; - } - `) - }) - }) - - test('using underscores as spaces', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--my-var\:2px_4px\] { - --my-var: 2px 4px; - } - `) - }) - }) - - test('using the important modifier', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\!\[--my-var\:2px_4px\] { - --my-var: 2px 4px !important; - } - `) - }) - }) - - test('colons are allowed in quotes', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[content\:\'foo\:bar\'\] { - content: 'foo:bar'; - } - `) - }) - }) - - test('colons are allowed in braces', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[background-image\:url\(http\:\/\/example\.com\/picture\.jpg\)\] { - background-image: url('http://example.com/picture.jpg'); - } - `) - }) - }) - - test('invalid class', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('invalid arbitrary property', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('invalid arbitrary property 2', () => { - let config = { - content: [ - { - raw: html`[0:02]`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('using fractional spacing values inside theme() function', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[border\:_calc\(5vw_-_theme\(spacing\[2\.5\]\)\)_double_theme\(\'colors\.fuchsia\.700\'\)\] { - border: calc(5vw - 0.625rem) double #a21caf; - } - `) - }) - }) - - test('using multiple arbitrary props having fractional spacing values', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[box-shadow\:_0_calc\(theme\(spacing\[0\.5\]\)_\*_-1\)_theme\(colors\.red\.400\)_inset\] { - box-shadow: inset 0 -0.125rem #f87171; - } - .\[height\:_calc\(100vh_-_theme\(spacing\[2\.5\]\)\)\] { - height: calc(100vh - 0.625rem); - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary properties (without quotes)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--a\:theme\(colors\.blue\.500\)\] { - --a: #3b82f6; - } - .\[color\:var\(--a\)\] { - color: var(--a); - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary properties (with quotes)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[--a\:theme\(\'colors\.blue\.500\'\)\] { - --a: #3b82f6; - } - .\[color\:var\(--a\)\] { - color: var(--a); - } - `) - }) - }) - - it('should not generate invalid CSS', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
- `, - - // NOTE: In this case `stillworks:/example` being generated is not ideal - // but it at least doesn't produce invalid CSS when run through prettier - // So we can let it through since it is technically valid - }, - ], - corePlugins: { preflight: false }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .\[stillworks\:\/example\] { - stillworks: /example; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[paint-order\:markers\] { + paint-order: markers; + } + `) + }) +}) + +test('different arbitrary properties are picked up separately', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[bar\:baz\] { + bar: baz; + } + .\[foo\:bar\] { + foo: bar; + } + `) + }) +}) + +test('arbitrary properties with modifiers', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + @media (min-width: 1024px) { + .dark\:lg\:hover\:\[paint-order\:markers\]:hover { + paint-order: markers; + } + } + } + `) + }) +}) + +test('arbitrary properties are sorted after utilities', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .content-none { + --tw-content: none; + content: var(--tw-content); + } + .\[paint-order\:markers\] { + paint-order: markers; + } + .hover\:pointer-events-none:hover { + pointer-events: none; + } + `) + }) +}) + +test('using CSS variables', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--my-var\:auto\] { + --my-var: auto; + } + `) + }) +}) + +test('using underscores as spaces', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--my-var\:2px_4px\] { + --my-var: 2px 4px; + } + `) + }) +}) + +test('using the important modifier', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\!\[--my-var\:2px_4px\] { + --my-var: 2px 4px !important; + } + `) + }) +}) + +test('colons are allowed in quotes', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[content\:\'foo\:bar\'\] { + content: 'foo:bar'; + } + `) + }) +}) + +test('colons are allowed in braces', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[background-image\:url\(http\:\/\/example\.com\/picture\.jpg\)\] { + background-image: url('http://example.com/picture.jpg'); + } + `) + }) +}) + +test('invalid class', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('invalid arbitrary property', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('invalid arbitrary property 2', () => { + let config = { + content: [ + { + raw: html`[0:02]`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('using fractional spacing values inside theme() function', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[border\:_calc\(5vw_-_theme\(spacing\[2\.5\]\)\)_double_theme\(\'colors\.fuchsia\.700\'\)\] { + border: calc(5vw - 0.625rem) double #a21caf; + } + `) + }) +}) + +test('using multiple arbitrary props having fractional spacing values', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[box-shadow\:_0_calc\(theme\(spacing\[0\.5\]\)_\*_-1\)_theme\(colors\.red\.400\)_inset\] { + box-shadow: inset 0 -0.125rem #f87171; + } + .\[height\:_calc\(100vh_-_theme\(spacing\[2\.5\]\)\)\] { + height: calc(100vh - 0.625rem); + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary properties (without quotes)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--a\:theme\(colors\.blue\.500\)\] { + --a: #3b82f6; + } + .\[color\:var\(--a\)\] { + color: var(--a); + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary properties (with quotes)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[--a\:theme\(\'colors\.blue\.500\'\)\] { + --a: #3b82f6; + } + .\[color\:var\(--a\)\] { + color: var(--a); + } + `) + }) +}) + +it('should not generate invalid CSS', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+ `, + + // NOTE: In this case `stillworks:/example` being generated is not ideal + // but it at least doesn't produce invalid CSS when run through prettier + // So we can let it through since it is technically valid + }, + ], + corePlugins: { preflight: false }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .\[stillworks\:\/example\] { + stillworks: /example; + } + `) }) }) diff --git a/tests/arbitrary-values.oxide.test.css b/tests/arbitrary-values.oxide.test.css deleted file mode 100644 index 214d08601..000000000 --- a/tests/arbitrary-values.oxide.test.css +++ /dev/null @@ -1,1073 +0,0 @@ -.inset-\[11px\] { - inset: 11px; -} -.inset-\[var\(--value\)\] { - inset: var(--value); -} -.inset-x-\[11px\] { - left: 11px; - right: 11px; -} -.inset-x-\[var\(--value\)\] { - left: var(--value); - right: var(--value); -} -.inset-y-\[11px\] { - top: 11px; - bottom: 11px; -} -.inset-y-\[var\(--value\)\] { - top: var(--value); - bottom: var(--value); -} -.bottom-\[11px\] { - bottom: 11px; -} -.bottom-\[var\(--value\)\] { - bottom: var(--value); -} -.left-\[11px\] { - left: 11px; -} -.left-\[var\(--value\)\] { - left: var(--value); -} -.right-\[11px\] { - right: 11px; -} -.right-\[var\(--value\)\] { - right: var(--value); -} -.top-\[11px\] { - top: 11px; -} -.top-\[var\(--value\)\] { - top: var(--value); -} -.z-\[123\] { - z-index: 123; -} -.z-\[var\(--value\)\] { - z-index: var(--value); -} -.order-\[4\] { - order: 4; -} -.order-\[var\(--value\)\] { - order: var(--value); -} -.col-\[7\] { - grid-column: 7; -} -.col-start-\[7\] { - grid-column-start: 7; -} -.col-end-\[7\] { - grid-column-end: 7; -} -.row-\[7\] { - grid-row: 7; -} -.row-start-\[7\] { - grid-row-start: 7; -} -.row-end-\[7\] { - grid-row-end: 7; -} -.m-\[7px\] { - margin: 7px; -} -.mx-\[7px\] { - margin-left: 7px; - margin-right: 7px; -} -.my-\[7px\] { - margin-top: 7px; - margin-bottom: 7px; -} -.mb-\[7px\] { - margin-bottom: 7px; -} -.ml-\[7px\] { - margin-left: 7px; -} -.mr-\[7px\] { - margin-right: 7px; -} -.mt-\[7px\] { - margin-top: 7px; -} -.mt-\[clamp\(30px\,100px\)\] { - margin-top: clamp(30px, 100px); -} -.aspect-\[16\/9\] { - aspect-ratio: 16 / 9; -} -.aspect-\[var\(--aspect\)\] { - aspect-ratio: var(--aspect); -} -.h-\[3\.23rem\] { - height: 3.23rem; -} -.h-\[calc\(100\%\+1rem\)\] { - height: calc(100% + 1rem); -} -.h-\[var\(--height\)\] { - height: var(--height); -} -.max-h-\[3\.23rem\] { - max-height: 3.23rem; -} -.max-h-\[calc\(100\%\+1rem\)\] { - max-height: calc(100% + 1rem); -} -.max-h-\[var\(--height\)\] { - max-height: var(--height); -} -.min-h-\[3\.23rem\] { - min-height: 3.23rem; -} -.min-h-\[calc\(100\%\+1rem\)\] { - min-height: calc(100% + 1rem); -} -.min-h-\[var\(--height\)\] { - min-height: var(--height); -} -.w-\[\'\)\(\)\'\] { - width: ')()'; -} -.w-\[\'\]\[\]\'\] { - width: '][]'; -} -.w-\[\'\}\{\}\'\] { - width: '}{}'; -} -.w-\[\(\(\)\)\] { - width: (()); -} -.w-\[\(\)\] { - width: (); -} -.w-\[0\] { - width: 0; -} -.w-\[3\.23rem\] { - width: 3.23rem; -} -.w-\[\[\[\]\]\] { - width: [[]]; -} -.w-\[\[\]\] { - width: []; -} -.w-\[calc\(100\%\+1rem\)\] { - width: calc(100% + 1rem); -} -.w-\[calc\(100\%\/3-1rem\*2\)\] { - width: calc(33.3333% - 2rem); -} -.w-\[calc\(var\(--10-10px\,calc\(-20px-\(-30px--40px\)\)\)-50px\)\] { - width: calc(var(--10-10px, calc(-20px - (-30px - -40px))) - 50px); -} -.w-\[var\(--width\)\] { - width: var(--width); -} -.w-\[var\(--width\,calc\(100\%\+1rem\)\)\] { - width: var(--width, calc(100% + 1rem)); -} -.w-\[\{\{\}\}\] { - width: {{}} -} -.w-\[\{\}\] { - width: {} -} -.min-w-\[3\.23rem\] { - min-width: 3.23rem; -} -.min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] { - min-width: -3.5px; -} -.min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] { - min-width: calc(1 - (var(--something) * 0.5)); -} -.min-w-\[calc\(1-var\(--something\)\*0\.5\)\] { - min-width: calc(1 - var(--something) * 0.5); -} -.min-w-\[calc\(100\%\+1rem\)\] { - min-width: calc(100% + 1rem); -} -.min-w-\[var\(--width\)\] { - min-width: var(--width); -} -.max-w-\[3\.23rem\] { - max-width: 3.23rem; -} -.max-w-\[calc\(100\%\+1rem\)\] { - max-width: calc(100% + 1rem); -} -.max-w-\[var\(--width\)\] { - max-width: var(--width); -} -.flex-\[var\(--flex\)\] { - flex: var(--flex); -} -.flex-shrink-\[var\(--shrink\)\], -.shrink-\[var\(--shrink\)\] { - flex-shrink: var(--shrink); -} -.flex-grow-\[var\(--grow\)\], -.grow-\[var\(--grow\)\] { - flex-grow: var(--grow); -} -.basis-\[var\(--basis\)\] { - flex-basis: var(--basis); -} -.origin-\[50px_50px\] { - transform-origin: 50px 50px; -} -.translate-x-\[12\%\] { - --tw-translate-x: 12%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-x-\[var\(--value\)\] { - --tw-translate-x: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-\[12\%\] { - --tw-translate-y: 12%; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-\[var\(--value\)\] { - --tw-translate-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[1\.5turn\] { - --tw-rotate: 1.5turn; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[2\.3rad\] { - --tw-rotate: 131.78deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[23deg\] { - --tw-rotate: 23deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-\[401grad\] { - --tw-rotate: 401grad; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-\[3px\] { - --tw-skew-x: 3px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-\[var\(--value\)\] { - --tw-skew-x: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-\[3px\] { - --tw-skew-y: 3px; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-\[var\(--value\)\] { - --tw-skew-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-\[0\.7\] { - --tw-scale-x: 0.7; - --tw-scale-y: 0.7; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-\[var\(--value\)\] { - --tw-scale-x: var(--value); - --tw-scale-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-x-\[0\.7\] { - --tw-scale-x: 0.7; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-x-\[var\(--value\)\] { - --tw-scale-x: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-y-\[0\.7\] { - --tw-scale-y: 0.7; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-y-\[var\(--value\)\] { - --tw-scale-y: var(--value); - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.animate-\[pong_1s_cubic-bezier\(0\,0\,0\.2\,1\)_infinite\] { - animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite pong; -} -.animate-\[var\(--value\)\] { - animation: var(--value); -} -.cursor-\[pointer\] { - cursor: pointer; -} -.cursor-\[url\(\'\.\/path_to_hand\.cur\'\)_2_2\,pointer\] { - cursor: url('./path_to_hand.cur') 2 2, pointer; -} -.cursor-\[url\(hand\.cur\)_2_2\,pointer\] { - cursor: url('hand.cur') 2 2, pointer; -} -.cursor-\[var\(--value\)\] { - cursor: var(--value); -} -.scroll-m-\[7px\] { - scroll-margin: 7px; -} -.scroll-mx-\[7px\] { - scroll-margin-left: 7px; - scroll-margin-right: 7px; -} -.scroll-my-\[7px\] { - scroll-margin-top: 7px; - scroll-margin-bottom: 7px; -} -.scroll-mb-\[7px\] { - scroll-margin-bottom: 7px; -} -.scroll-ml-\[7px\] { - scroll-margin-left: 7px; -} -.scroll-mr-\[7px\] { - scroll-margin-right: 7px; -} -.scroll-mt-\[7px\] { - scroll-margin-top: 7px; -} -.scroll-mt-\[var\(--scroll-margin\)\] { - scroll-margin-top: var(--scroll-margin); -} -.scroll-p-\[7px\] { - scroll-padding: 7px; -} -.scroll-px-\[7px\] { - scroll-padding-left: 7px; - scroll-padding-right: 7px; -} -.scroll-py-\[7px\] { - scroll-padding-top: 7px; - scroll-padding-bottom: 7px; -} -.scroll-pb-\[7px\] { - scroll-padding-bottom: 7px; -} -.scroll-pl-\[7px\] { - scroll-padding-left: 7px; -} -.scroll-pr-\[7px\] { - scroll-padding-right: 7px; -} -.scroll-pt-\[7px\] { - scroll-padding-top: 7px; -} -.scroll-pt-\[var\(--scroll-padding\)\] { - scroll-padding-top: var(--scroll-padding); -} -.list-\[\'\\1f44d\'\] { - list-style-type: '👍'; -} -.list-\[var\(--value\)\] { - list-style-type: var(--value); -} -.list-image-\[url\(\.\/my-image\.png\)\] { - list-style-image: url('./my-image.png'); -} -.list-image-\[var\(--value\)\] { - list-style-image: var(--value); -} -.columns-\[20\] { - columns: 20; -} -.columns-\[var\(--columns\)\] { - columns: var(--columns); -} -.auto-cols-\[minmax\(10px\,auto\)\] { - grid-auto-columns: minmax(10px, auto); -} -.auto-rows-\[minmax\(10px\,auto\)\] { - grid-auto-rows: minmax(10px, auto); -} -.grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; -} -.grid-cols-\[\[linename\]\,1fr\,auto\] { - grid-template-columns: [linename] 1fr auto; -} -.grid-rows-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; -} -.gap-\[20px\] { - gap: 20px; -} -.gap-\[var\(--value\)\] { - gap: var(--value); -} -.gap-x-\[20px\] { - column-gap: 20px; -} -.gap-x-\[var\(--value\)\] { - column-gap: var(--value); -} -.gap-y-\[20px\] { - row-gap: 20px; -} -.gap-y-\[var\(--value\)\] { - row-gap: var(--value); -} -.space-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(20cm * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(20cm * var(--tw-space-x-reverse)); -} -.space-x-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(calc(20% - 1cm) * var(--tw-space-x-reverse)); -} -.space-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(20cm * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(20cm * var(--tw-space-y-reverse)); -} -.space-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(calc(20% - 1cm) * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(calc(20% - 1cm) * var(--tw-space-y-reverse)); -} -.divide-x-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(20cm * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(20cm * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-x-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(calc(20% - 1cm) * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-y-\[20cm\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(20cm * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(20cm * var(--tw-divide-y-reverse)); -} -.divide-y-\[calc\(20\%-1cm\)\] > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(calc(20% - 1cm) * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(calc(20% - 1cm) * var(--tw-divide-y-reverse)); -} -.divide-\[black\] > :not([hidden]) ~ :not([hidden]) { - border-color: #000; -} -.divide-\[var\(--value\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: var(--value); -} -.rounded-\[11px\] { - border-radius: 11px; -} -.rounded-b-\[var\(--radius\)\] { - border-bottom-right-radius: var(--radius); - border-bottom-left-radius: var(--radius); -} -.rounded-l-\[var\(--radius\)\] { - border-top-left-radius: var(--radius); - border-bottom-left-radius: var(--radius); -} -.rounded-r-\[var\(--radius\)\] { - border-top-right-radius: var(--radius); - border-bottom-right-radius: var(--radius); -} -.rounded-t-\[var\(--radius\)\] { - border-top-left-radius: var(--radius); - border-top-right-radius: var(--radius); -} -.rounded-bl-\[var\(--radius\)\] { - border-bottom-left-radius: var(--radius); -} -.rounded-br-\[var\(--radius\)\] { - border-bottom-right-radius: var(--radius); -} -.rounded-tl-\[var\(--radius\)\] { - border-top-left-radius: var(--radius); -} -.rounded-tr-\[var\(--radius\)\] { - border-top-right-radius: var(--radius); -} -.border-\[2\.5px\] { - border-width: 2.5px; -} -.border-\[length\:var\(--value\)\] { - border-width: var(--value); -} -.border-b-\[2\.5px\] { - border-bottom-width: 2.5px; -} -.border-b-\[length\:var\(--value\)\] { - border-bottom-width: var(--value); -} -.border-l-\[2\.5px\] { - border-left-width: 2.5px; -} -.border-l-\[length\:var\(--value\)\] { - border-left-width: var(--value); -} -.border-r-\[2\.5px\] { - border-right-width: 2.5px; -} -.border-r-\[length\:var\(--value\)\] { - border-right-width: var(--value); -} -.border-t-\[2\.5px\] { - border-top-width: 2.5px; -} -.border-t-\[length\:var\(--value\)\] { - border-top-width: var(--value); -} -.border-\[\#f00\] { - border-color: red; -} -.border-\[color\:var\(--value\)\] { - border-color: var(--value); -} -.border-\[red_black\] { - border-color: red #000; -} -.border-b-\[\#f00\] { - border-bottom-color: red; -} -.border-b-\[color\:var\(--value\)\] { - border-bottom-color: var(--value); -} -.border-l-\[\#f00\] { - border-left-color: red; -} -.border-l-\[color\:var\(--value\)\] { - border-left-color: var(--value); -} -.border-r-\[\#f00\] { - border-right-color: red; -} -.border-r-\[color\:var\(--value\)\] { - border-right-color: var(--value); -} -.border-t-\[\#f00\] { - border-top-color: red; -} -.border-t-\[color\:var\(--value\)\] { - border-top-color: var(--value); -} -.bg-\[\#0000ffcc\] { - background-color: #00fc; -} -.bg-\[\#0f0\] { - background-color: #0f0; -} -.bg-\[\#0f0_var\(--value\)\] { - background-color: #0f0 var(--value); -} -.bg-\[\#ff0000\] { - background-color: red; -} -.bg-\[color\:var\(--value1\)_var\(--value2\)\] { - background-color: var(--value1) var(--value2); -} -.bg-\[hsl\(0\,100\%\,50\%\)\], -.bg-\[hsl\(0rad\,100\%\,50\%\)\] { - background-color: red; -} -.bg-\[hsla\(0\,100\%\,50\%\,0\.3\)\], -.bg-\[hsla\(0turn\,100\%\,50\%\,0\.3\)\] { - background-color: #ff00004d; -} -.bg-\[rgb\(123\,123\,123\)\] { - background-color: #7b7b7b; -} -.bg-\[rgb\(123\,_456\,_123\)_black\] { - background-color: #7bff7b black; -} -.bg-\[rgb\(123_456_789\)\] { - background-color: #7bffff; -} -.bg-\[rgba\(123\,123\,123\,0\.5\)\] { - background-color: #7b7b7b80; -} -.bg-\[var\(--value\)\,var\(--value\)\] { - background-color: var(--value), var(--value); -} -.bg-\[var\(--value1\)_var\(--value2\)\] { - background-color: var(--value1) var(--value2); -} -.bg-\[image\(\)\,var\(--value\)\] { - background-image: image(), var(--value); -} -.bg-\[image\:var\(--value\)\,var\(--value\)\] { - background-image: var(--value), var(--value); -} -.bg-\[linear-gradient\(\#eee\,\#fff\)\,conic-gradient\(red\,orange\,yellow\,green\,blue\)\] { - background-image: linear-gradient(#eee, #fff), conic-gradient(red, orange, #ff0, green, #00f); -} -.bg-\[linear-gradient\(\#eee\,\#fff\)\] { - background-image: linear-gradient(#eee, #fff); -} -.bg-\[linear-gradient\(to_left\,rgb\(var\(--green\)\)\,blue\)\] { - background-image: linear-gradient(to left, rgb(var(--green)), blue); -} -.bg-\[repeating-conic-gradient\(\#F8F9FA_0\%_25\%\,_white_0\%_50\%\)\] { - background-image: repeating-conic-gradient(#f8f9fa 0% 25%, white 0% 50%); -} -.bg-\[url\(\'\/path-to-image\.png\'\)\] { - background-image: url('/path-to-image.png'); -} -.bg-\[url\:var\(--url\)\] { - background-image: var(--url); -} -.from-\[\#da5b66\] { - --tw-gradient-from: #da5b66 var(--tw-gradient-from-position); - --tw-gradient-to: #da5b6600 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.from-\[var\(--color\)\] { - --tw-gradient-from: var(--color) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.via-\[\#da5b66\] { - --tw-gradient-to: #da5b6600 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #da5b66 var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.via-\[var\(--color\)\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--color) var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.to-\[\#da5b66\] { - --tw-gradient-to: #da5b66 var(--tw-gradient-to-position); -} -.to-\[var\(--color\)\] { - --tw-gradient-to: var(--color) var(--tw-gradient-to-position); -} -.bg-\[length\:200px_100px\] { - background-size: 200px 100px; -} -.bg-\[length\:var\(--value\)\] { - background-size: var(--value); -} -.bg-\[center_top_1rem\] { - background-position: 50% 1rem; -} -.bg-\[position\:200px_100px\] { - background-position: 200px 100px; -} -.bg-\[position\:var\(--value\)\] { - background-position: var(--value); -} -.fill-\[\#da5b66\] { - fill: #da5b66; -} -.fill-\[url\(\#icon-gradient\)\] { - fill: url('#icon-gradient'); -} -.fill-\[var\(--value\)\] { - fill: var(--value); -} -.stroke-\[\#da5b66\] { - stroke: #da5b66; -} -.stroke-\[color\:var\(--value\)\] { - stroke: var(--value); -} -.stroke-\[url\(\#icon-gradient\)\] { - stroke: url('#icon-gradient'); -} -.stroke-\[20px\] { - stroke-width: 20px; -} -.stroke-\[length\:var\(--value\)\] { - stroke-width: var(--value); -} -.object-\[50\%\,50\%\] { - object-position: 50% 50%; -} -.object-\[top\,right\] { - object-position: top right; -} -.object-\[var\(--position\)\] { - object-position: var(--position); -} -.p-\[7px\] { - padding: 7px; -} -.px-\[7px\] { - padding-left: 7px; - padding-right: 7px; -} -.py-\[7px\] { - padding-top: 7px; - padding-bottom: 7px; -} -.pb-\[7px\] { - padding-bottom: 7px; -} -.pl-\[7px\] { - padding-left: 7px; -} -.pr-\[7px\] { - padding-right: 7px; -} -.pt-\[7px\] { - padding-top: 7px; -} -.pt-\[clamp\(30px\,100px\)\] { - padding-top: clamp(30px, 100px); -} -.indent-\[50\%\] { - text-indent: 50%; -} -.indent-\[var\(--indent\)\] { - text-indent: var(--indent); -} -.align-\[10em\] { - vertical-align: 10em; -} -.font-\[\'Gill_Sans\'\] { - font-family: Gill Sans; -} -.font-\[\'Some_Font\'\,\'Some_Other_Font\'\] { - font-family: Some Font, Some Other Font; -} -.font-\[\'Some_Font\'\,sans-serif\] { - font-family: Some Font, sans-serif; -} -.font-\[\'Some_Font\'\,var\(--other-font\)\] { - font-family: 'Some Font', var(--other-font); -} -.font-\[Georgia\,serif\] { - font-family: Georgia, serif; -} -.font-\[family-name\:var\(--value\)\] { - font-family: var(--value); -} -.font-\[sans-serif\,serif\] { - font-family: sans-serif, serif; -} -.font-\[serif\,var\(--value\)\] { - font-family: serif, var(--value); -} -.text-\[0\] { - font-size: 0; -} -.text-\[2\.23rem\] { - font-size: 2.23rem; -} -.text-\[4cqw\] { - font-size: 4cqw; -} -.text-\[length\:var\(--font-size\)\] { - font-size: var(--font-size); -} -.text-\[min\(10vh\,100px\)\] { - font-size: min(10vh, 100px); -} -.font-\[300\] { - font-weight: 300; -} -.font-\[number\:lighter\] { - font-weight: lighter; -} -.font-\[number\:var\(--value\)\] { - font-weight: var(--value); -} -.leading-\[var\(--leading\)\] { - line-height: var(--leading); -} -.tracking-\[var\(--tracking\)\] { - letter-spacing: var(--tracking); -} -.text-\[black\] { - color: #000; -} -.text-\[color\:var\(--color\)\] { - color: var(--color); -} -.text-\[rgb\(123\,123\,123\)\], -.text-\[rgb\(123\,_123\,_123\)\], -.text-\[rgb\(123_123_123\)\] { - color: #7b7b7b; -} -.decoration-\[black\] { - text-decoration-color: #000; -} -.decoration-\[color\:var\(--color\)\] { - text-decoration-color: var(--color); -} -.decoration-\[rgb\(123\,123\,123\)\], -.decoration-\[rgb\(123\,_123\,_123\)\], -.decoration-\[rgb\(123_123_123\)\] { - text-decoration-color: #7b7b7b; -} -.decoration-\[length\:10px\] { - text-decoration-thickness: 10px; -} -.underline-offset-\[10px\] { - text-underline-offset: 10px; -} -.placeholder-\[var\(--placeholder\)\]::placeholder { - color: var(--placeholder); -} -.caret-\[black\] { - caret-color: #000; -} -.caret-\[var\(--value\)\] { - caret-color: var(--value); -} -.accent-\[\#bada55\] { - accent-color: #bada55; -} -.accent-\[var\(--accent-color\)\] { - accent-color: var(--accent-color); -} -.opacity-\[0\.8\] { - opacity: 0.8; -} -.opacity-\[var\(--opacity\)\] { - opacity: var(--opacity); -} -.shadow-\[0px_1px_2px_black\] { - --tw-shadow: 0px 1px 2px black; - --tw-shadow-colored: 0px 1px 2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-\[shadow\:var\(--value\)\] { - --tw-shadow: var(--value); - --tw-shadow-colored: var(--value); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.outline-\[10px\] { - outline-width: 10px; -} -.outline-\[length\:var\(--outline\)\] { - outline-width: var(--outline); -} -.outline-offset-\[10px\] { - outline-offset: 10px; -} -.outline-\[black\] { - outline-color: #000; -} -.outline-\[color\:var\(--outline\)\] { - outline-color: var(--outline); -} -.ring-\[10px\] { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(10px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-\[length\:\(var\(--value\)\)\] { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc((var(--value)) + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-\[\#76ad65\] { - --tw-ring-color: #76ad65; -} -.ring-\[color\:var\(--value\)\] { - --tw-ring-color: var(--value); -} -.ring-offset-\[19rem\] { - --tw-ring-offset-width: 19rem; -} -.ring-offset-\[length\:var\(--value\)\] { - --tw-ring-offset-width: var(--value); -} -.ring-offset-\[\#76ad65\] { - --tw-ring-offset-color: #76ad65; -} -.ring-offset-\[\#ad672f\] { - --tw-ring-offset-color: #ad672f; -} -.ring-offset-\[color\:var\(--value\)\] { - --tw-ring-offset-color: var(--value); -} -.blur-\[15px\] { - --tw-blur: blur(15px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.brightness-\[300\%\] { - --tw-brightness: brightness(300%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.contrast-\[2\.4\] { - --tw-contrast: contrast(2.4); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.drop-shadow-\[0px_1px_2px_black\] { - --tw-drop-shadow: drop-shadow(0px 1px 2px black); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.grayscale-\[0\.55\] { - --tw-grayscale: grayscale(0.55); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.hue-rotate-\[0\.8turn\] { - --tw-hue-rotate: hue-rotate(0.8turn); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.invert-\[0\.75\] { - --tw-invert: invert(0.75); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.saturate-\[180\%\] { - --tw-saturate: saturate(180%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.sepia-\[0\.2\] { - --tw-sepia: sepia(0.2); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.backdrop-blur-\[11px\] { - --tw-backdrop-blur: blur(11px); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-brightness-\[1\.23\] { - --tw-backdrop-brightness: brightness(1.23); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-contrast-\[0\.87\] { - --tw-backdrop-contrast: contrast(0.87); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-grayscale-\[0\.42\] { - --tw-backdrop-grayscale: grayscale(0.42); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-hue-rotate-\[1\.57rad\] { - --tw-backdrop-hue-rotate: hue-rotate(89.9544deg); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-invert-\[0\.66\] { - --tw-backdrop-invert: invert(0.66); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-opacity-\[22\%\] { - --tw-backdrop-opacity: opacity(22%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-saturate-\[144\%\] { - --tw-backdrop-saturate: saturate(144%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-sepia-\[0\.38\] { - --tw-backdrop-sepia: sepia(0.38); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.transition-\[opacity\,width\] { - transition-property: opacity, width; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.delay-\[var\(--delay\)\] { - transition-delay: var(--delay); -} -.duration-\[2s\] { - transition-duration: 2s; -} -.duration-\[var\(--app-duration\)\] { - transition-duration: var(--app-duration); -} -.will-change-\[top\,left\] { - will-change: top, left; -} -.will-change-\[var\(--will-change\)\] { - will-change: var(--will-change); -} -.content-\[\'\>\'\] { - --tw-content: '>'; - content: var(--tw-content); -} -.content-\[\'hello\'\] { - --tw-content: 'hello'; - content: var(--tw-content); -} -.content-\[attr\(content-before\)\] { - --tw-content: attr(content-before); - content: var(--tw-content); -} -@media (min-width: 1024px) { - .lg\:grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } -} diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index 6f43a5277..32646e5ff 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -185,7 +185,7 @@ min-width: 3.23rem; } .min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] { - min-width: calc(1 - ((12 - 3) * 0.5)); + min-width: -3.5px; } .min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] { min-width: calc(1 - (var(--something) * 0.5)); diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js index 774b4db40..923607517 100644 --- a/tests/arbitrary-values.test.js +++ b/tests/arbitrary-values.test.js @@ -1,655 +1,612 @@ import fs from 'fs' import path from 'path' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('arbitrary values', () => { - let config = { - content: [path.resolve(__dirname, './arbitrary-values.test.html')], - } +test('arbitrary values', () => { + let config = { + content: [path.resolve(__dirname, './arbitrary-values.test.html')], + } - return run('@tailwind utilities', config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './arbitrary-values.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './arbitrary-values.oxide.test.css'), 'utf8') - ) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './arbitrary-values.test.css'), 'utf8') + ) }) +}) - oxide.test.todo( - 'should only detect classes with arbitrary values that are properly terminated after the arbitrary value' - ) - stable.test( - 'should only detect classes with arbitrary values that are properly terminated after the arbitrary value', - () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], +test('should only detect classes with arbitrary values that are properly terminated after the arbitrary value', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) + }) +}) + +it('should be possible to differentiate between decoration utilities', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .decoration-\[\#ccc\] { + text-decoration-color: #ccc; } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css``) - }) - } - ) - - it('should be possible to differentiate between decoration utilities', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .decoration-\[\#ccc\] { - text-decoration-color: #ccc; - } - .decoration-\[3px\] { - text-decoration-thickness: 3px; - } - `) - }) + .decoration-\[3px\] { + text-decoration-thickness: 3px; + } + `) }) +}) - it('should support modifiers for arbitrary values that contain the separator', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } +it('should support modifiers for arbitrary values that contain the separator', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .hover\:bg-\[url\(\'https\:\/\/github\.com\/tailwindlabs\.png\'\)\]:hover { - background-image: url('https://github.com/tailwindlabs.png'); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .hover\:bg-\[url\(\'https\:\/\/github\.com\/tailwindlabs\.png\'\)\]:hover { + background-image: url('https://github.com/tailwindlabs.png'); + } + `) }) +}) - it('should support arbitrary values for various background utilities', () => { - let config = { - content: [ - { - raw: html` - -
-
+it('should support arbitrary values for various background utilities', () => { + let config = { + content: [ + { + raw: html` + +
+
- -
-
-
-
+ +
+
+
+
- -
-
- `, - }, - ], - } + +
+
+ `, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#ff0000\] { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - .bg-\[color\:var\(--bg-color\)\] { - background-color: var(--bg-color); - } - .bg-\[hsl\(var\(--bg-color\)\)\] { - background-color: hsl(var(--bg-color)); - } - .bg-\[rgb\(var\(--bg-color\)\)\] { - background-color: rgb(var(--bg-color)); - } - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .bg-\[url\(\'\/image-1-0\.png\'\)\] { - background-image: url('/image-1-0.png'); - } - .bg-\[url\:var\(--image-url\)\] { - background-image: var(--image-url); - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#ff0000\] { - background-color: red; - } - .bg-\[color\:var\(--bg-color\)\] { - background-color: var(--bg-color); - } - .bg-\[hsl\(var\(--bg-color\)\)\] { - background-color: hsl(var(--bg-color)); - } - .bg-\[rgb\(var\(--bg-color\)\)\] { - background-color: rgb(var(--bg-color)); - } - .bg-red-500 { - background-color: #ef4444; - } - .bg-\[url\(\'\/image-1-0\.png\'\)\] { - background-image: url('/image-1-0.png'); - } - .bg-\[url\:var\(--image-url\)\] { - background-image: var(--image-url); - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[\#ff0000\] { + --tw-bg-opacity: 1; + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); + } + .bg-\[color\:var\(--bg-color\)\] { + background-color: var(--bg-color); + } + .bg-\[hsl\(var\(--bg-color\)\)\] { + background-color: hsl(var(--bg-color)); + } + .bg-\[rgb\(var\(--bg-color\)\)\] { + background-color: rgb(var(--bg-color)); + } + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + .bg-\[url\(\'\/image-1-0\.png\'\)\] { + background-image: url('/image-1-0.png'); + } + .bg-\[url\:var\(--image-url\)\] { + background-image: var(--image-url); + } + .bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); + } + `) }) +}) - it('should not generate any css if an unknown typehint is used', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } +it('should not generate any css if an unknown typehint is used', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css``) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) }) +}) - it('should handle unknown typehints', () => { - let config = { content: [{ raw: html`
` }] } +it('should handle unknown typehints', () => { + let config = { content: [{ raw: html`
` }] } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[length\:12px\] { - width: 12px; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[length\:12px\] { + width: 12px; + } + `) }) +}) - it('should convert _ to spaces', () => { - // Using custom css function here, because otherwise with String.raw, we run - // into an issue with `\2c ` escapes. If we use `\2c ` then JS complains - // about strict mode. But `\\2c ` is not what it expected. - function css(templates) { - return templates.join('') - } +it('should convert _ to spaces', () => { + // Using custom css function here, because otherwise with String.raw, we run + // into an issue with `\2c ` escapes. If we use `\2c ` then JS complains + // about strict mode. But `\\2c ` is not what it expected. + function css(templates) { + return templates.join('') + } - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .col-\\[span_3_\\/_span_8\\] { - grid-column: span 3 / span 8; - } - .row-\\[span_3_\\/_span_8\\] { - grid-row: span 3 / span 8; - } - .m-\\[8px_4px\\] { - margin: 8px 4px; - } - .flex-\\[1_1_100\\%\\] { - flex: 100%; - } - .auto-cols-\\[minmax\\(0\\,_1fr\\)\\] { - grid-auto-columns: minmax(0, 1fr); - } - .grid-cols-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .grid-rows-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { - grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .rounded-\\[0px_4px_4px_0px\\] { - border-radius: 0 4px 4px 0; - } - .p-\\[8px_4px\\] { - padding: 8px 4px; - } - .shadow-\\[0px_0px_4px_black\\] { - --tw-shadow: 0px 0px 4px black; - --tw-shadow-colored: 0px 0px 4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .drop-shadow-\\[0px_1px_3px_black\\] { - --tw-drop-shadow: drop-shadow(0px 1px 3px black); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) - var(--tw-drop-shadow); - } - .content-\\[\\'__hello__world__\\'\\] { - --tw-content: ' hello world '; - content: var(--tw-content); - } - .content-\\[___abc____\\] { - --tw-content: abc; - content: var(--tw-content); - } - .content-\\[_hello_world_\\] { - --tw-content: hello world; - content: var(--tw-content); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .col-\\[span_3_\\/_span_8\\] { + grid-column: span 3 / span 8; + } + .row-\\[span_3_\\/_span_8\\] { + grid-row: span 3 / span 8; + } + .m-\\[8px_4px\\] { + margin: 8px 4px; + } + .flex-\\[1_1_100\\%\\] { + flex: 100%; + } + .auto-cols-\\[minmax\\(0\\,_1fr\\)\\] { + grid-auto-columns: minmax(0, 1fr); + } + .grid-cols-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { + grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; + } + .grid-rows-\\[200px_repeat\\(auto-fill\\,minmax\\(15\\%\\,100px\\)\\)_300px\\] { + grid-template-rows: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; + } + .rounded-\\[0px_4px_4px_0px\\] { + border-radius: 0 4px 4px 0; + } + .p-\\[8px_4px\\] { + padding: 8px 4px; + } + .shadow-\\[0px_0px_4px_black\\] { + --tw-shadow: 0px 0px 4px black; + --tw-shadow-colored: 0px 0px 4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .drop-shadow-\\[0px_1px_3px_black\\] { + --tw-drop-shadow: drop-shadow(0px 1px 3px black); + filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) + var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) + var(--tw-drop-shadow); + } + .content-\\[\\'__hello__world__\\'\\] { + --tw-content: ' hello world '; + content: var(--tw-content); + } + .content-\\[___abc____\\] { + --tw-content: abc; + content: var(--tw-content); + } + .content-\\[_hello_world_\\] { + --tw-content: hello world; + content: var(--tw-content); + } + `) }) +}) - it('should not convert escaped underscores with spaces', () => { - let config = { - content: [{ raw: `
` }], - corePlugins: { preflight: false }, - } +it('should not convert escaped underscores with spaces', () => { + let config = { + content: [{ raw: `
` }], + corePlugins: { preflight: false }, + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .content-\[\'snake\\_case\'\] { - --tw-content: 'snake_case'; - content: var(--tw-content); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .content-\[\'snake\\_case\'\] { + --tw-content: 'snake_case'; + content: var(--tw-content); + } + `) }) +}) - it('should pick the fallback plugin when arbitrary values collide', () => { - let config = { - content: [ - { - raw: html` -
- -
- -
-
- `, - }, - ], - } +it('should pick the fallback plugin when arbitrary values collide', () => { + let config = { + content: [ + { + raw: html` +
+ +
+ +
+
+ `, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .bg-\[var\(--unknown\)\] { - background-color: var(--unknown); - } - .bg-\[200px_100px\] { - background-position: 200px 100px; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[var\(--unknown\)\] { + background-color: var(--unknown); + } + .bg-\[200px_100px\] { + background-position: 200px 100px; + } + `) }) +}) - it('should pick the fallback plugin when arbitrary values collide and can not be inferred', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should pick the fallback plugin when arbitrary values collide and can not be inferred', () => { + let config = { + content: [{ raw: html`
` }], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .bg-\[var\(--tw-unknown\)\] { - background-color: var(--tw-unknown); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[var\(--tw-unknown\)\] { + background-color: var(--tw-unknown); + } + `) }) +}) - it('should warn and not generate if arbitrary values are ambiguous (without fallback)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ matchUtilities }) { - matchUtilities({ foo: (value) => ({ value }) }, { type: ['position'] }) - matchUtilities({ foo: (value) => ({ value }) }, { type: ['size'] }) - }, - ], - } +it('should warn and not generate if arbitrary values are ambiguous (without fallback)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ matchUtilities }) { + matchUtilities({ foo: (value) => ({ value }) }, { type: ['position'] }) + matchUtilities({ foo: (value) => ({ value }) }, { type: ['size'] }) + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css``) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css``) }) +}) - it('should support colons in URLs', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } +it('should support colons in URLs', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .bg-\[url\(\'https\:\/\/www\.spacejam\.com\/1996\/img\/bg_stars\.gif\'\)\] { - background-image: url('https://www.spacejam.com/1996/img/bg_stars.gif'); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .bg-\[url\(\'https\:\/\/www\.spacejam\.com\/1996\/img\/bg_stars\.gif\'\)\] { + background-image: url('https://www.spacejam.com/1996/img/bg_stars.gif'); + } + `) }) +}) - it('should support unescaped underscores in URLs', () => { - let config = { - content: [ - { raw: html`
` }, - ], - } +it('should support unescaped underscores in URLs', () => { + let config = { + content: [ + { raw: html`
` }, + ], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(` + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(` .bg-\\[url\\(\\'brown_potato\\.jpg\\'\\)\\,_url\\(\\'red_tomato\\.png\\'\\)\\] { background-image: url('brown_potato.jpg'), url('red_tomato.png'); } `) - }) - }) - - it('should be possible to read theme values in arbitrary values (without quotes)', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - spacing: { - 0.5: 'calc(.5 * .25rem)', - 1: 'calc(1 * .25rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[theme\(spacing\.1\)\] { - width: 0.25rem; - } - .w-\[theme\(spacing\[0\.5\]\)\] { - width: 0.125rem; - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary values (with quotes)', () => { - let config = { - content: [ - { raw: html`
` }, - ], - theme: { - spacing: { - 0.5: 'calc(.5 * .25rem)', - 1: 'calc(1 * .25rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[theme\(\'spacing\.1\'\)\] { - width: 0.25rem; - } - .w-\[theme\(\'spacing\[0\.5\]\'\)\] { - width: 0.125rem; - } - `) - }) - }) - - it('should be possible to read theme values in arbitrary values (with quotes) when inside calc or similar functions', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - theme: { - spacing: { - 0.5: 'calc(.5 * .25rem)', - 1: 'calc(1 * .25rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .w-\[calc\(100\%-theme\(\'spacing\.1\'\)\)\] { - width: calc(100% - 0.25rem); - } - .w-\[calc\(100\%-theme\(\'spacing\[0\.5\]\'\)\)\] { - width: calc(100% - 0.125rem); - } - `) - }) - }) - - it('should not output unparsable arbitrary CSS values', () => { - let config = { - content: [ - { - raw: 'let classes = `w-[${sizes.width}]`', - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(``) - }) - }) - - // Issue: https://github.com/tailwindlabs/tailwindcss/issues/7997 - // `top_right_50%` was a valid percentage before introducing this change - it('should correctly validate each part when checking for `percentage` data types', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[top_right_50\%\] { - background-position: right 50% top; - } - `) - }) - }) - - it('should correctly validate background size', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[auto_auto\,cover\,_contain\,10px\,10px_10\%\] { - background-size: auto, cover, contain, 10px, 10px 10%; - } - `) - }) - }) - - it('should correctly validate combination of percentage and length', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[50\%_10\%\] { - background-position: 50% 10%; - } - .bg-\[50px_10\%\] { - background-position: 50px 10%; - } - .bg-\[50px_10px\] { - background-position: 50px 10px; - } - `) - }) - }) - - it('can explicitly specify type for percentage and length', () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[size\:50px_10\%\] { - background-size: 50px 10%; - } - .bg-\[50px_10px\] { - background-position: 50px 10px; - } - .bg-\[position\:50\%_10\%\] { - background-position: 50% 10%; - } - `) - }) - }) - - it('can use CSS variables as arbitrary values without `var()`', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .w-\[--width-var\] { - width: var(--width-var); - } - .bg-\[--color-var\,\#000\] { - background-color: var(--color-var, #000); - } - .bg-\[--color-var\] { - background-color: var(--color-var); - } - .bg-\[length\:--size-var\] { - background-size: var(--size-var); - } - .text-\[length\:--size-var\,12px\] { - font-size: var(--size-var, 12px); - } - `) - }) - }) - - it('can use CSS variables as arbitrary modifiers without `var()`', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/\[--opacity\] { - background-color: rgb(239 68 68 / var(--opacity)); - } - .text-sm\/\[--line-height\] { - font-size: 0.875rem; - line-height: var(--line-height); - } - `) - }) - }) - - it('should support underscores in arbitrary modifiers', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-lg\/\[calc\(50px_\*_2\)\] { - font-size: 1.125rem; - line-height: calc(50px * 2); - } - `) - }) + }) +}) + +it('should be possible to read theme values in arbitrary values (without quotes)', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + spacing: { + 0.5: 'calc(.5 * .25rem)', + 1: 'calc(1 * .25rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[theme\(spacing\.1\)\] { + width: 0.25rem; + } + .w-\[theme\(spacing\[0\.5\]\)\] { + width: 0.125rem; + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary values (with quotes)', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + spacing: { + 0.5: 'calc(.5 * .25rem)', + 1: 'calc(1 * .25rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[theme\(\'spacing\.1\'\)\] { + width: 0.25rem; + } + .w-\[theme\(\'spacing\[0\.5\]\'\)\] { + width: 0.125rem; + } + `) + }) +}) + +it('should be possible to read theme values in arbitrary values (with quotes) when inside calc or similar functions', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + theme: { + spacing: { + 0.5: 'calc(.5 * .25rem)', + 1: 'calc(1 * .25rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .w-\[calc\(100\%-theme\(\'spacing\.1\'\)\)\] { + width: calc(100% - 0.25rem); + } + .w-\[calc\(100\%-theme\(\'spacing\[0\.5\]\'\)\)\] { + width: calc(100% - 0.125rem); + } + `) + }) +}) + +it('should not output unparsable arbitrary CSS values', () => { + let config = { + content: [ + { + raw: 'let classes = `w-[${sizes.width}]`', + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(``) + }) +}) + +// Issue: https://github.com/tailwindlabs/tailwindcss/issues/7997 +// `top_right_50%` was a valid percentage before introducing this change +it('should correctly validate each part when checking for `percentage` data types', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[top_right_50\%\] { + background-position: right 50% top; + } + `) + }) +}) + +it('should correctly validate background size', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[auto_auto\,cover\,_contain\,10px\,10px_10\%\] { + background-size: auto, cover, contain, 10px, 10px 10%; + } + `) + }) +}) + +it('should correctly validate combination of percentage and length', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[50\%_10\%\] { + background-position: 50% 10%; + } + .bg-\[50px_10\%\] { + background-position: 50px 10%; + } + .bg-\[50px_10px\] { + background-position: 50px 10px; + } + `) + }) +}) + +it('can explicitly specify type for percentage and length', () => { + let config = { + content: [ + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[size\:50px_10\%\] { + background-size: 50px 10%; + } + .bg-\[50px_10px\] { + background-position: 50px 10px; + } + .bg-\[position\:50\%_10\%\] { + background-position: 50% 10%; + } + `) + }) +}) + +it('can use CSS variables as arbitrary values without `var()`', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .w-\[--width-var\] { + width: var(--width-var); + } + .bg-\[--color-var\,\#000\] { + background-color: var(--color-var, #000); + } + .bg-\[--color-var\] { + background-color: var(--color-var); + } + .bg-\[length\:--size-var\] { + background-size: var(--size-var); + } + .text-\[length\:--size-var\,12px\] { + font-size: var(--size-var, 12px); + } + `) + }) +}) + +it('can use CSS variables as arbitrary modifiers without `var()`', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/\[--opacity\] { + background-color: rgb(239 68 68 / var(--opacity)); + } + .text-sm\/\[--line-height\] { + font-size: 0.875rem; + line-height: var(--line-height); + } + `) + }) +}) + +it('should support underscores in arbitrary modifiers', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-lg\/\[calc\(50px_\*_2\)\] { + font-size: 1.125rem; + line-height: calc(50px * 2); + } + `) }) }) diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index b210bdc77..1e37a5047 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -1,377 +1,372 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('basic arbitrary variants', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('basic arbitrary variants', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\>\*\]\:underline > * { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\>\*\]\:underline > * { + text-decoration-line: underline; + } + `) }) +}) - test('spaces in selector (using _)', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('spaces in selector (using _)', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .a.b .\[\.a\.b_\&\]\:underline { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .a.b .\[\.a\.b_\&\]\:underline { + text-decoration-line: underline; + } + `) }) +}) - test('arbitrary variants with modifiers', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('arbitrary variants with modifiers', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - @media (min-width: 1024px) { - .dark\:lg\:hover\:\[\&\>\*\]\:underline > :hover { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - test('variants without & or an at-rule are ignored', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - `) - }) - }) - - test('arbitrary variants are sorted after other variants', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .underline { - text-decoration-line: underline; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { @media (min-width: 1024px) { - .lg\:underline { + .dark\:lg\:hover\:\[\&\>\*\]\:underline > :hover { text-decoration-line: underline; } } - .\[\&\>\*\]\:underline > * { + } + `) + }) +}) + +test('variants without & or an at-rule are ignored', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + `) + }) +}) + +test('arbitrary variants are sorted after other variants', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .underline { + text-decoration-line: underline; + } + @media (min-width: 1024px) { + .lg\:underline { text-decoration-line: underline; } - `) - }) + } + .\[\&\>\*\]\:underline > * { + text-decoration-line: underline; + } + `) }) +}) - test('using the important modifier', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('using the important modifier', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\>\*\]\:\!underline > * { - text-decoration-line: underline !important; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\>\*\]\:\!underline > * { + text-decoration-line: underline !important; + } + `) + }) +}) + +test('at-rules', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @supports (what: ever) { + .\[\@supports\(what\:ever\)\]\:underline { + text-decoration-line: underline; } - `) - }) + } + `) }) +}) - test('at-rules', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('nested at-rules', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @supports (what: ever) { - .\[\@supports\(what\:ever\)\]\:underline { - text-decoration-line: underline; - } - } - `) - }) - }) - - test('nested at-rules', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media screen { - @media (hover: hover) { - .\[\@media_screen\{\@media\(hover\:hover\)\}\]\:underline { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - test('at-rules with selector modifications', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media screen { @media (hover: hover) { - .\[\@media\(hover\:hover\)\{\&\:hover\}\]\:underline:hover { + .\[\@media_screen\{\@media\(hover\:hover\)\}\]\:underline { text-decoration-line: underline; } } - `) - }) + } + `) }) +}) - test('nested at-rules with selector modifications', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('at-rules with selector modifications', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media screen { - @media (hover: hover) { - .\[\@media_screen\{\@media\(hover\:hover\)\{\&\:hover\}\}\]\:underline:hover { - text-decoration-line: underline; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (hover: hover) { + .\[\@media\(hover\:hover\)\{\&\:hover\}\]\:underline:hover { + text-decoration-line: underline; + } + } + `) + }) +}) + +test('nested at-rules with selector modifications', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media screen { + @media (hover: hover) { + .\[\@media_screen\{\@media\(hover\:hover\)\{\&\:hover\}\}\]\:underline:hover { + text-decoration-line: underline; } } - `) - }) + } + `) }) +}) - test('attribute selectors', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('attribute selectors', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-open\]\]\:underline[data-open] { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-open\]\]\:underline[data-open] { + text-decoration-line: underline; + } + `) }) +}) - test('multiple attribute selectors', () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } +test('multiple attribute selectors', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]\:underline[data-foo][data-bar]:not([data-baz]) { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]\:underline[data-foo][data-bar]:not([data-baz]) { + text-decoration-line: underline; + } + `) }) +}) - oxide.test.todo('multiple attribute selectors with custom separator (1)') - stable.test('multiple attribute selectors with custom separator (1)', () => { - let config = { - separator: '__', - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } +test('multiple attribute selectors with custom separator (1)', () => { + let config = { + separator: '__', + content: [ + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]__underline[data-foo][data-bar]:not([data-baz]) { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]__underline[data-foo][data-bar]:not([data-baz]) { + text-decoration-line: underline; + } + `) }) +}) - oxide.test.todo('multiple attribute selectors with custom separator (2)') - stable.test('multiple attribute selectors with custom separator (2)', () => { - let config = { - separator: '_@', - content: [ - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } +test('multiple attribute selectors with custom separator (2)', () => { + let config = { + separator: '_@', + content: [ + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]_\@underline[data-foo][data-bar]:not([data-baz]) { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-foo\]\[data-bar\]\:not\(\[data-baz\]\)\]_\@underline[data-foo][data-bar]:not([data-baz]) { + text-decoration-line: underline; + } + `) }) +}) - test('with @apply', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +test('with @apply', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = ` + let input = ` @tailwind base; @tailwind components; @tailwind utilities; @@ -381,138 +376,138 @@ crosscheck(({ stable, oxide }) => { } ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media screen { - @media (hover: hover) { - .foo:hover { - text-decoration-line: underline; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media screen { + @media (hover: hover) { + .foo:hover { + text-decoration-line: underline; } } - `) - }) + } + `) }) +}) - test('keeps escaped underscores', () => { - let config = { - content: [ - { - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } +test('keeps escaped underscores', () => { + let config = { + content: [ + { + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&_\.foo\\_\\_bar\]\:underline .foo__bar { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&_\.foo\\_\\_bar\]\:underline .foo__bar { + text-decoration-line: underline; + } + `) }) +}) - test('keeps escaped underscores with multiple arbitrary variants', () => { - let config = { - content: [ - { - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } +test('keeps escaped underscores with multiple arbitrary variants', () => { + let config = { + content: [ + { + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&_\.foo\\_\\_bar\]\:\[\&_\.bar\\_\\_baz\]\:underline .bar__baz .foo__bar { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&_\.foo\\_\\_bar\]\:\[\&_\.bar\\_\\_baz\]\:underline .bar__baz .foo__bar { + text-decoration-line: underline; + } + `) }) +}) - test('keeps escaped underscores in arbitrary variants mixed with normal variants', () => { - let config = { - content: [ - { - raw: ` +test('keeps escaped underscores in arbitrary variants mixed with normal variants', () => { + let config = { + content: [ + { + raw: `
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&_\.foo\\_\\_bar\]\:hover\:underline:hover .foo__bar, + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&_\.foo\\_\\_bar\]\:hover\:underline:hover .foo__bar, .hover\:\[\&_\.foo\\_\\_bar\]\:underline .foo__bar:hover { - text-decoration-line: underline; - } - `) - }) + text-decoration-line: underline; + } + `) }) +}) - test('allows attribute variants with quotes', () => { - let config = { - content: [ - { - raw: ` +test('allows attribute variants with quotes', () => { + let config = { + content: [ + { + raw: `
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .\[\&\[data-test\=\"2\"\]\]\:underline[data-test='2'], + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\[\&\[data-test\=\"2\"\]\]\:underline[data-test='2'], .\[\&\[data-test\=\'2\'\]\]\:underline[data-test='2'] { - text-decoration-line: underline; - } - `) - }) + text-decoration-line: underline; + } + `) }) +}) - test('classes in arbitrary variants should not be prefixed', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: ` +test('classes in arbitrary variants should not be prefixed', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: `
should not be red
should be red
@@ -530,731 +525,662 @@ crosscheck(({ stable, oxide }) => {
should be red
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-text-red-400 .foo, - .\[\&_\.foo\]\:hover\:tw-text-red-400:hover .foo, - .hover\:\[\&_\.foo\]\:tw-text-red-400 .foo:hover, - .foo .\[\.foo_\&\]\:tw-text-red-400 { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-text-red-400 .foo, - .\[\&_\.foo\]\:hover\:tw-text-red-400:hover .foo, - .hover\:\[\&_\.foo\]\:tw-text-red-400 .foo:hover, - .foo .\[\.foo_\&\]\:tw-text-red-400 { - color: #f87171; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\[\&_\.foo\]\:tw-text-red-400 .foo, + .\[\&_\.foo\]\:hover\:tw-text-red-400:hover .foo, + .hover\:\[\&_\.foo\]\:tw-text-red-400 .foo:hover, + .foo .\[\.foo_\&\]\:tw-text-red-400 { + --tw-text-opacity: 1; + color: rgb(248 113 113 / var(--tw-text-opacity)); + } + `) }) +}) - test('classes in the same arbitrary variant should not be prefixed', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: ` -
should not be red
+test('classes in the same arbitrary variant should not be prefixed', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: ` +
should not be red
-
should be red
+
should be red
-
+
should not be red
should be red
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-bg-white .foo { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - .\[\&_\.foo\]\:tw-text-red-400 .foo { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - .foo .\[\.foo_\&\]\:tw-bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - .foo .\[\.foo_\&\]\:tw-text-red-400 { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\[\&_\.foo\]\:tw-bg-white .foo { - background-color: #fff; - } - .\[\&_\.foo\]\:tw-text-red-400 .foo { - color: #f87171; - } - .foo .\[\.foo_\&\]\:tw-bg-white { - background-color: #fff; - } - .foo .\[\.foo_\&\]\:tw-text-red-400 { - color: #f87171; - } - `) - }) - }) - - it('should support aria variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .underline, - .aria-checked\:underline[aria-checked='true'], - .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], - .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], - .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, - .group[aria-checked='true'] .group-aria-checked\:underline, - .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, - .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, - .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, - .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, - .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, - .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, - .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, - .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { - text-decoration-line: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .aria-checked\:underline[aria-checked='true'], - .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], - .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], - .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, - .group[aria-checked='true'] .group-aria-checked\:underline, - .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, - .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, - .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, - .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, - .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, - .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, - .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, - .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should support data variants', () => { - let config = { - theme: { - data: { - checked: 'ui~="checked"', - }, }, - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .underline, - .data-checked\:underline[data-ui~='checked'], - .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], - .data-\[position\=top\]\:underline[data-position='top'], - .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, - .group[data-ui~='checked'] .group-data-checked\:underline, - .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, - .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, - .group[data-position='top'] .group-data-\[position\=top\]\:underline, - .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, - .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, - .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, - .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, - .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { - text-decoration-line: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .data-checked\:underline[data-ui~='checked'], - .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], - .data-\[position\=top\]\:underline[data-position='top'], - .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, - .group[data-ui~='checked'] .group-data-checked\:underline, - .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, - .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, - .group[data-position='top'] .group-data-\[position\=top\]\:underline, - .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, - .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, - .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, - .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, - .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\[\&_\.foo\]\:tw-font-bold .foo, + .foo .\[\.foo_\&\]\:tw-font-bold { + font-weight: 700; + } + `) }) +}) - it('should support supports', () => { - let config = { - theme: { - supports: { - grid: 'display: grid', - }, +it('should support aria variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, }, - content: [ - { - raw: html` -
- -
- -
- -
- -
- -
- -
- -
- -
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @supports (display: grid) { - .supports-grid\:underline { - text-decoration-line: underline; - } - .supports-\[display\:grid\]\:grid { - display: grid; - } - } - @supports (foo: bar) and (bar: baz) { - .supports-\[\(foo\:bar\)and\(bar\:baz\)\]\:underline { - text-decoration-line: underline; - } - } - @supports (foo: bar) or (bar: baz) { - .supports-\[\(foo\:bar\)or\(bar\:baz\)\]\:underline { - text-decoration-line: underline; - } - } - @supports (container-type: var(--tw)) { - .supports-\[container-type\]\:underline { - text-decoration-line: underline; - } - } - @supports not (foo: bar) { - .supports-\[not\(foo\:bar\)\]\:underline { - text-decoration-line: underline; - } - } - @supports selector(A > B) { - .supports-\[selector\(A_\>_B\)\]\:underline { - text-decoration-line: underline; - } - } - @supports (transform-origin: 5% 5%) { - .supports-\[transform-origin\:5\%_5\%\]\:underline { - text-decoration-line: underline; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .underline, + .aria-checked\:underline[aria-checked='true'], + .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], + .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], + .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, + .group[aria-checked='true'] .group-aria-checked\:underline, + .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, + .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, + .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, + .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, + .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, + .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, + .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, + .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { + text-decoration-line: underline; + } + `) }) +}) - it('should be possible to use modifiers and arbitrary groups', () => { - let config = { - content: [ - { - raw: html` -
-
- -
+it('should support data variants', () => { + let config = { + theme: { + data: { + checked: 'ui~="checked"', + }, + }, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - - -
- -
+ let input = css` + @tailwind utilities; + ` - - -
- -
+ return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .underline, + .data-checked\:underline[data-ui~='checked'], + .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], + .data-\[position\=top\]\:underline[data-position='top'], + .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, + .group[data-ui~='checked'] .group-data-checked\:underline, + .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, + .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, + .group[data-position='top'] .group-data-\[position\=top\]\:underline, + .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, + .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, + .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, + .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, + .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { + text-decoration-line: underline; + } + `) + }) +}) - - -
- -
-
+it('should support supports', () => { + let config = { + theme: { + supports: { + grid: 'display: grid', + }, + }, + content: [ + { + raw: html` +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - -
-
+ let input = css` + @tailwind utilities; + ` -
-
- -
-
- -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .group\/foo:hover .group-hover\/foo\:underline, - .group:hover .group-hover\:underline, - .group\/foo:focus .group-\[\&\:focus\]\/foo\:underline, - .group:focus .group-\[\&\:focus\]\:underline, - .group\/foo[data-open] .group-\[\&\[data-open\]\]\/foo\:underline, - .group[data-open] .group-\[\&\[data-open\]\]\:underline, - .group\/foo.in-foo .group-\[\.in-foo\]\/foo\:underline, - .group.in-foo .group-\[\.in-foo\]\:underline, - .in-foo .group\/foo .group-\[\.in-foo_\&\]\/foo\:underline, - .in-foo .group .group-\[\.in-foo_\&\]\:underline, - .group\/foo:hover .group-\[\:hover\]\/foo\:underline, - .group:hover .group-\[\:hover\]\:underline, - .group\/foo[data-open] .group-\[\[data-open\]\]\/foo\:underline, - .group[data-open] .group-\[\[data-open\]\]\:underline { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @supports (display: grid) { + .supports-grid\:underline { text-decoration-line: underline; } - `) - }) + .supports-\[display\:grid\]\:grid { + display: grid; + } + } + @supports (foo: bar) and (bar: baz) { + .supports-\[\(foo\:bar\)and\(bar\:baz\)\]\:underline { + text-decoration-line: underline; + } + } + @supports (foo: bar) or (bar: baz) { + .supports-\[\(foo\:bar\)or\(bar\:baz\)\]\:underline { + text-decoration-line: underline; + } + } + @supports (container-type: var(--tw)) { + .supports-\[container-type\]\:underline { + text-decoration-line: underline; + } + } + @supports not (foo: bar) { + .supports-\[not\(foo\:bar\)\]\:underline { + text-decoration-line: underline; + } + } + @supports selector(A > B) { + .supports-\[selector\(A_\>_B\)\]\:underline { + text-decoration-line: underline; + } + } + @supports (transform-origin: 5% 5%) { + .supports-\[transform-origin\:5\%_5\%\]\:underline { + text-decoration-line: underline; + } + } + `) }) +}) - it('should be possible to use modifiers and arbitrary peers', () => { - let config = { - content: [ - { - raw: html` -
-
+it('should be possible to use modifiers and arbitrary groups', () => { + let config = { + content: [ + { + raw: html` +
+
+ +
- -
- - + -
+
-
+
- + -
+
-
+
-
+
-
- - -
- -
- -
-
- -
-
- -
-
+
- `, - }, - ], - corePlugins: { preflight: false }, - } - let input = css` - @tailwind utilities; - ` + +
+
- return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .peer\/foo:hover ~ .peer-hover\/foo\:underline, - .peer:hover ~ .peer-hover\:underline, - .peer\/foo:focus ~ .peer-\[\&\:focus\]\/foo\:underline, - .peer:focus ~ .peer-\[\&\:focus\]\:underline, - .peer\/foo[data-open] ~ .peer-\[\&\[data-open\]\]\/foo\:underline, - .peer[data-open] ~ .peer-\[\&\[data-open\]\]\:underline, - .peer\/foo.in-foo ~ .peer-\[\.in-foo\]\/foo\:underline, - .peer.in-foo ~ .peer-\[\.in-foo\]\:underline, - .in-foo .peer\/foo ~ .peer-\[\.in-foo_\&\]\/foo\:underline, - .in-foo .peer ~ .peer-\[\.in-foo_\&\]\:underline, - .peer\/foo:hover ~ .peer-\[\:hover\]\/foo\:underline, - .peer:hover ~ .peer-\[\:hover\]\:underline, - .peer\/foo[data-open] ~ .peer-\[\[data-open\]\]\/foo\:underline, - .peer[data-open] ~ .peer-\[\[data-open\]\]\:underline { - text-decoration-line: underline; - } - `) - }) - }) +
+
- it('Arbitrary variants are ordered alphabetically', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
+
+
+ +
+
- `, - }, - ], - corePlugins: { preflight: false }, - } +
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .\[\&\:\:a\]\:underline::a { - text-decoration-line: underline; - } - .\[\&\:\:b\]\:underline::b { - text-decoration-line: underline; - } - .\[\&\:\:c\]\:underline::c { - text-decoration-line: underline; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group\/foo:hover .group-hover\/foo\:underline, + .group:hover .group-hover\:underline, + .group\/foo:focus .group-\[\&\:focus\]\/foo\:underline, + .group:focus .group-\[\&\:focus\]\:underline, + .group\/foo[data-open] .group-\[\&\[data-open\]\]\/foo\:underline, + .group[data-open] .group-\[\&\[data-open\]\]\:underline, + .group\/foo.in-foo .group-\[\.in-foo\]\/foo\:underline, + .group.in-foo .group-\[\.in-foo\]\:underline, + .in-foo .group\/foo .group-\[\.in-foo_\&\]\/foo\:underline, + .in-foo .group .group-\[\.in-foo_\&\]\:underline, + .group\/foo:hover .group-\[\:hover\]\/foo\:underline, + .group:hover .group-\[\:hover\]\:underline, + .group\/foo[data-open] .group-\[\[data-open\]\]\/foo\:underline, + .group[data-open] .group-\[\[data-open\]\]\:underline { + text-decoration-line: underline; + } + `) }) +}) - it('Arbitrary variants support multiple attribute selectors', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +it('should be possible to use modifiers and arbitrary peers', () => { + let config = { + content: [ + { + raw: html` +
+
- let input = css` - @tailwind utilities; - ` + +
- return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - [data-foo='bar'][data-baz] .\[\[data-foo\=\'bar\'\]\[data-baz\]_\&\]\:underline { - text-decoration-line: underline; - } - `) - }) + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
+ +
+ +
+
+ +
+
+ +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .peer\/foo:hover ~ .peer-hover\/foo\:underline, + .peer:hover ~ .peer-hover\:underline, + .peer\/foo:focus ~ .peer-\[\&\:focus\]\/foo\:underline, + .peer:focus ~ .peer-\[\&\:focus\]\:underline, + .peer\/foo[data-open] ~ .peer-\[\&\[data-open\]\]\/foo\:underline, + .peer[data-open] ~ .peer-\[\&\[data-open\]\]\:underline, + .peer\/foo.in-foo ~ .peer-\[\.in-foo\]\/foo\:underline, + .peer.in-foo ~ .peer-\[\.in-foo\]\:underline, + .in-foo .peer\/foo ~ .peer-\[\.in-foo_\&\]\/foo\:underline, + .in-foo .peer ~ .peer-\[\.in-foo_\&\]\:underline, + .peer\/foo:hover ~ .peer-\[\:hover\]\/foo\:underline, + .peer:hover ~ .peer-\[\:hover\]\:underline, + .peer\/foo[data-open] ~ .peer-\[\[data-open\]\]\/foo\:underline, + .peer[data-open] ~ .peer-\[\[data-open\]\]\:underline { + text-decoration-line: underline; + } + `) }) +}) - it('Invalid arbitrary variants selectors should produce nothing instead of failing', () => { - let config = { - content: [ - { - raw: html` +it('Arbitrary variants are ordered alphabetically', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\[\&\:\:a\]\:underline::a { + text-decoration-line: underline; + } + .\[\&\:\:b\]\:underline::b { + text-decoration-line: underline; + } + .\[\&\:\:c\]\:underline::c { + text-decoration-line: underline; + } + `) + }) +}) + +it('Arbitrary variants support multiple attribute selectors', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + [data-foo='bar'][data-baz] .\[\[data-foo\=\'bar\'\]\[data-baz\]_\&\]\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('Invalid arbitrary variants selectors should produce nothing instead of failing', () => { + let config = { + content: [ + { + raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css``) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) }) +}) - it('should output responsive variants + stacked variants in the right order', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +it('should output responsive variants + stacked variants in the right order', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 1280px) { - .xl\:p-1 { - padding: 0.25rem; - } - } - .\[\&_ul\]\:flex ul { - display: flex; - } - .\[\&_ul\]\:flex-col ul { - flex-direction: column; - } - @media (min-width: 768px) { - .md\:\[\&_ul\]\:flex-row ul { - flex-direction: row; - } - } - `) - }) - }) - - it('it should discard arbitrary variants with multiple selectors', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - { - // escaped commas are a-ok - // This is separate because prettier complains about `\,` in the template string - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .p-1, - .span\,div .hover\:\[\.span\\\,div_\&\]\:p-1:hover, - :is(span, div) .hover\:\[\:is\(span\,div\)_\&\]\:p-1:hover, - div .\[div_\&\]\:p-1, - div .hover\:\[div_\&\]\:p-1:hover { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 1280px) { + .xl\:p-1 { padding: 0.25rem; } - `) - }) + } + .\[\&_ul\]\:flex ul { + display: flex; + } + .\[\&_ul\]\:flex-col ul { + flex-direction: column; + } + @media (min-width: 768px) { + .md\:\[\&_ul\]\:flex-row ul { + flex-direction: row; + } + } + `) }) +}) - it('should sort multiple variant fns with normal variants between them', () => { - /** @type {string[]} */ - let lines = [] +it('it should discard arbitrary variants with multiple selectors', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + { + // escaped commas are a-ok + // This is separate because prettier complains about `\,` in the template string + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } - for (let a of [1, 2]) { - for (let b of [2, 1]) { - for (let c of [1, 2]) { - for (let d of [2, 1]) { - for (let e of [1, 2]) { - lines.push(`
`) - } + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .p-1, + .span\,div .hover\:\[\.span\\\,div_\&\]\:p-1:hover, + :is(span, div) .hover\:\[\:is\(span\,div\)_\&\]\:p-1:hover, + div .\[div_\&\]\:p-1, + div .hover\:\[div_\&\]\:p-1:hover { + padding: 0.25rem; + } + `) + }) +}) + +it('should sort multiple variant fns with normal variants between them', () => { + /** @type {string[]} */ + let lines = [] + + for (let a of [1, 2]) { + for (let b of [2, 1]) { + for (let c of [1, 2]) { + for (let d of [2, 1]) { + for (let e of [1, 2]) { + lines.push(`
`) } } } } + } - // Fisher-Yates shuffle - for (let i = lines.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * i) - ;[lines[i], lines[j]] = [lines[j], lines[i]] - } + // Fisher-Yates shuffle + for (let i = lines.length - 1; i > 0; i--) { + let j = Math.floor(Math.random() * i) + ;[lines[i], lines[j]] = [lines[j], lines[i]] + } - let config = { - content: [ - { - raw: lines.join('\n'), - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addVariant, matchVariant }) { - addVariant('foo1', "&[data-foo='1']") - addVariant('foo2', "&[data-foo='2']") + let config = { + content: [ + { + raw: lines.join('\n'), + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addVariant, matchVariant }) { + addVariant('foo1', "&[data-foo='1']") + addVariant('foo2', "&[data-foo='2']") - matchVariant('bar', (value) => `&[data-bar='${value}']`, { - sort: (a, b) => b.value - a.value, - }) + matchVariant('bar', (value) => `&[data-bar='${value}']`, { + sort: (a, b) => b.value - a.value, + }) - addVariant('baz1', "&[data-baz='1']") - addVariant('baz2', "&[data-baz='2']") + addVariant('baz1', "&[data-baz='1']") + addVariant('baz2', "&[data-baz='2']") - matchVariant('qux', (value) => `&[data-qux='${value}']`, { - sort: (a, b) => b.value - a.value, - }) + matchVariant('qux', (value) => `&[data-qux='${value}']`, { + sort: (a, b) => b.value - a.value, + }) - addVariant('fred1', "&[data-fred='1']") - addVariant('fred2', "&[data-fred='2']") - }, - ], - } + addVariant('fred1', "&[data-fred='1']") + addVariant('fred2', "&[data-fred='2']") + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], - .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'], - .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] { - padding: 0.25rem; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred1\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='1'], + .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[2\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='2'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz1\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='1'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo1\:p-1[data-foo='1'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[2\]\:foo2\:p-1[data-foo='2'][data-bar='2'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo1\:p-1[data-foo='1'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'], + .fred2\:qux-\[1\]\:baz2\:bar-\[1\]\:foo2\:p-1[data-foo='2'][data-bar='1'][data-baz='2'][data-qux='1'][data-fred='2'] { + padding: 0.25rem; + } + `) }) }) diff --git a/tests/basic-usage.oxide.test.css b/tests/basic-usage.oxide.test.css deleted file mode 100644 index 6a01dc045..000000000 --- a/tests/basic-usage.oxide.test.css +++ /dev/null @@ -1,1028 +0,0 @@ -*, -:before, -:after, -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #3b82f680; - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} -.container { - width: 100%; -} -@media (min-width: 640px) { - .container { - max-width: 640px; - } -} -@media (min-width: 768px) { - .container { - max-width: 768px; - } -} -@media (min-width: 1024px) { - .container { - max-width: 1024px; - } -} -@media (min-width: 1280px) { - .container { - max-width: 1280px; - } -} -@media (min-width: 1536px) { - .container { - max-width: 1536px; - } -} -.sr-only { - width: 1px; - height: 1px; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; - margin: -1px; - padding: 0; - position: absolute; - overflow: hidden; -} -.pointer-events-none { - pointer-events: none; -} -.invisible { - visibility: hidden; -} -.collapse { - visibility: collapse; -} -.absolute { - position: absolute; -} -.inset-0 { - inset: 0; -} -.inset-x-2 { - left: 0.5rem; - right: 0.5rem; -} -.inset-y-4 { - top: 1rem; - bottom: 1rem; -} -.bottom-12 { - bottom: 3rem; -} -.left-16 { - left: 4rem; -} -.right-8 { - right: 2rem; -} -.top-6 { - top: 1.5rem; -} -.isolate { - isolation: isolate; -} -.isolation-auto { - isolation: auto; -} -.z-30 { - z-index: 30; -} -.order-2 { - order: 2; -} -.order-last { - order: 9999; -} -.col-span-3 { - grid-column: span 3 / span 3; -} -.col-start-1 { - grid-column-start: 1; -} -.col-end-4 { - grid-column-end: 4; -} -.row-span-2 { - grid-row: span 2 / span 2; -} -.row-start-3 { - grid-row-start: 3; -} -.row-end-5 { - grid-row-end: 5; -} -.float-right { - float: right; -} -.clear-left { - clear: left; -} -.m-4 { - margin: 1rem; -} -.mx-auto { - margin-left: auto; - margin-right: auto; -} -.my-2 { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.mb-3 { - margin-bottom: 0.75rem; -} -.ml-4 { - margin-left: 1rem; -} -.mr-1 { - margin-right: 0.25rem; -} -.mt-0 { - margin-top: 0; -} -.box-border { - box-sizing: border-box; -} -.inline-grid { - display: inline-grid; -} -.hidden { - display: none; -} -.aspect-square { - aspect-ratio: 1 / 1; -} -.aspect-video { - aspect-ratio: 16 / 9; -} -.h-16 { - height: 4rem; -} -.max-h-screen { - max-height: 100vh; -} -.min-h-0 { - min-height: 0; -} -.w-12 { - width: 3rem; -} -.min-w-min { - min-width: min-content; -} -.max-w-full { - max-width: 100%; -} -.flex-1 { - flex: 1; -} -.flex-shrink { - flex-shrink: 1; -} -.flex-shrink-0 { - flex-shrink: 0; -} -.shrink { - flex-shrink: 1; -} -.shrink-0 { - flex-shrink: 0; -} -.flex-grow { - flex-grow: 1; -} -.flex-grow-0 { - flex-grow: 0; -} -.grow { - flex-grow: 1; -} -.grow-0 { - flex-grow: 0; -} -.basis-7 { - flex-basis: 1.75rem; -} -.basis-auto { - flex-basis: auto; -} -.table-fixed { - table-layout: fixed; -} -.caption-top { - caption-side: top; -} -.caption-bottom { - caption-side: bottom; -} -.border-collapse { - border-collapse: collapse; -} -.border-spacing-4 { - --tw-border-spacing-x: 1rem; - --tw-border-spacing-y: 1rem; - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); -} -.border-spacing-x-6 { - --tw-border-spacing-x: 1.5rem; - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); -} -.border-spacing-y-8 { - --tw-border-spacing-y: 2rem; - border-spacing: var(--tw-border-spacing-x) var(--tw-border-spacing-y); -} -.origin-top-right { - transform-origin: 100% 0; -} -.-translate-x-3 { - --tw-translate-x: -0.75rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.-translate-x-4 { - --tw-translate-x: -1rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-x-5 { - --tw-translate-x: 1.25rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-6 { - --tw-translate-y: 1.5rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-12 { - --tw-skew-x: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-12 { - --tw-skew-y: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-95 { - --tw-scale-x: 0.95; - --tw-scale-y: 0.95; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.-scale-x-100 { - --tw-scale-x: -1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform-gpu { - transform: translate3d(var(--tw-translate-x), var(--tw-translate-y), 0) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform-none { - transform: none; -} -.animate-none { - animation: none; -} -@keyframes spin { - to { - transform: rotate(360deg); - } -} -.animate-spin { - animation: 1s linear infinite spin; -} -.cursor-pointer { - cursor: pointer; -} -.touch-pan-x { - --tw-pan-x: pan-x; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-pan-y { - --tw-pan-y: pan-y; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-pan-up { - --tw-pan-y: pan-up; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-pinch-zoom { - --tw-pinch-zoom: pinch-zoom; - touch-action: var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom); -} -.touch-manipulation { - touch-action: manipulation; -} -.select-none { - user-select: none; -} -.resize-none { - resize: none; -} -.snap-x { - scroll-snap-type: x var(--tw-scroll-snap-strictness); -} -.snap-mandatory { - --tw-scroll-snap-strictness: mandatory; -} -.snap-center { - scroll-snap-align: center; -} -.snap-always { - scroll-snap-stop: always; -} -.scroll-mt-6 { - scroll-margin-top: 1.5rem; -} -.scroll-p-6 { - scroll-padding: 1.5rem; -} -.list-inside { - list-style-position: inside; -} -.list-disc { - list-style-type: disc; -} -.list-image-none { - list-style-image: none; -} -.appearance-none { - appearance: none; -} -.columns-1 { - columns: 1; -} -.columns-md { - columns: 28rem; -} -.break-before-page { - break-before: page; -} -.break-inside-avoid-column { - break-inside: avoid-column; -} -.break-after-auto { - break-after: auto; -} -.auto-cols-min { - grid-auto-columns: min-content; -} -.grid-flow-row { - grid-auto-flow: row; -} -.auto-rows-max { - grid-auto-rows: max-content; -} -.grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); -} -.grid-rows-3 { - grid-template-rows: repeat(3, minmax(0, 1fr)); -} -.flex-row-reverse { - flex-direction: row-reverse; -} -.flex-wrap { - flex-wrap: wrap; -} -.place-content-start { - place-content: start; -} -.place-items-end { - place-items: end; -} -.content-center { - align-content: center; -} -.items-start { - align-items: flex-start; -} -.justify-center { - justify-content: center; -} -.justify-items-end { - justify-items: end; -} -.gap-4 { - gap: 1rem; -} -.gap-x-2 { - column-gap: 0.5rem; -} -.gap-y-3 { - row-gap: 0.75rem; -} -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); -} -.space-y-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); -} -.space-y-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 1; -} -.space-x-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 1; -} -.divide-x-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(0px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(0px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(2px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(2px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-y-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(0px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(0px * var(--tw-divide-y-reverse)); -} -.divide-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(4px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(4px * var(--tw-divide-y-reverse)); -} -.divide-dotted > :not([hidden]) ~ :not([hidden]) { - border-style: dotted; -} -.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { - border-color: #e5e7eb; -} -.place-self-center { - place-self: center; -} -.self-end { - align-self: flex-end; -} -.justify-self-start { - justify-self: start; -} -.overflow-hidden { - overflow: hidden; -} -.overscroll-contain { - overscroll-behavior: contain; -} -.truncate { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} -.overflow-ellipsis { - text-overflow: ellipsis; -} -.whitespace-nowrap { - white-space: nowrap; -} -.break-words { - overflow-wrap: break-word; -} -.rounded-md { - border-radius: 0.375rem; -} -.border { - border-width: 1px; -} -.border-2 { - border-width: 2px; -} -.border-x-4 { - border-left-width: 4px; - border-right-width: 4px; -} -.border-y-4 { - border-top-width: 4px; - border-bottom-width: 4px; -} -.border-b-4 { - border-bottom-width: 4px; -} -.border-t { - border-top-width: 1px; -} -.border-solid { - border-style: solid; -} -.border-hidden { - border-style: hidden; -} -.border-black { - border-color: #000; -} -.border-x-black { - border-left-color: #000; - border-right-color: #000; -} -.border-y-black { - border-top-color: #000; - border-bottom-color: #000; -} -.border-b-black { - border-bottom-color: #000; -} -.border-l-black { - border-left-color: #000; -} -.border-r-black { - border-right-color: #000; -} -.border-t-black { - border-top-color: #000; -} -.bg-green-500 { - background-color: #22c55e; -} -.bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); -} -.from-red-300 { - --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); - --tw-gradient-to: #fca5a500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.via-purple-200 { - --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.to-blue-400 { - --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); -} -.decoration-slice { - -webkit-box-decoration-break: slice; - box-decoration-break: slice; -} -.decoration-clone { - -webkit-box-decoration-break: clone; - box-decoration-break: clone; -} -.box-decoration-slice { - -webkit-box-decoration-break: slice; - box-decoration-break: slice; -} -.box-decoration-clone { - -webkit-box-decoration-break: clone; - box-decoration-break: clone; -} -.bg-cover { - background-size: cover; -} -.bg-local { - background-attachment: local; -} -.bg-clip-border { - background-clip: border-box; -} -.bg-top { - background-position: top; -} -.bg-no-repeat { - background-repeat: no-repeat; -} -.bg-origin-border { - background-origin: border-box; -} -.bg-origin-padding { - background-origin: padding-box; -} -.bg-origin-content { - background-origin: content-box; -} -.fill-current { - fill: currentColor; -} -.stroke-current { - stroke: currentColor; -} -.stroke-2 { - stroke-width: 2px; -} -.object-cover { - object-fit: cover; -} -.object-bottom { - object-position: bottom; -} -.p-4 { - padding: 1rem; -} -.px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} -.pb-3 { - padding-bottom: 0.75rem; -} -.pl-4 { - padding-left: 1rem; -} -.pr-2 { - padding-right: 0.5rem; -} -.pt-1 { - padding-top: 0.25rem; -} -.text-center { - text-align: center; -} -.-indent-12 { - text-indent: -3rem; -} -.indent-6 { - text-indent: 1.5rem; -} -.align-middle { - vertical-align: middle; -} -.font-sans { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, - Noto Color Emoji; -} -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} -.font-medium { - font-weight: 500; -} -.uppercase { - text-transform: uppercase; -} -.not-italic { - font-style: normal; -} -.ordinal { - --tw-ordinal: ordinal; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.diagonal-fractions { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.leading-5 { - line-height: 1.25rem; -} -.leading-relaxed { - line-height: 1.625; -} -.tracking-tight { - letter-spacing: -0.025em; -} -.text-indigo-500 { - color: #6366f1; -} -.underline { - text-decoration-line: underline; -} -.decoration-red-600 { - text-decoration-color: #dc2626; -} -.decoration-solid { - text-decoration-style: solid; -} -.decoration-1 { - text-decoration-thickness: 1px; -} -.decoration-2 { - text-decoration-thickness: 2px; -} -.underline-offset-1 { - text-underline-offset: 1px; -} -.underline-offset-2 { - text-underline-offset: 2px; -} -.antialiased { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.placeholder-green-300::placeholder { - color: #86efac; -} -.caret-red-600 { - caret-color: #dc2626; -} -.accent-red-600 { - accent-color: #dc2626; -} -.opacity-90 { - opacity: 0.9; -} -.bg-blend-darken { - background-blend-mode: darken; -} -.bg-blend-difference { - background-blend-mode: difference; -} -.mix-blend-multiply { - mix-blend-mode: multiply; -} -.mix-blend-saturation { - mix-blend-mode: saturation; -} -.shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-lg { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-black { - --tw-shadow-color: #000; - --tw-shadow: var(--tw-shadow-colored); -} -.shadow-blue-100\/10 { - --tw-shadow-color: #dbeafe1a; - --tw-shadow: var(--tw-shadow-colored); -} -.shadow-red-500\/25 { - --tw-shadow-color: #ef444440; - --tw-shadow: var(--tw-shadow-colored); -} -.outline-none { - outline-offset: 2px; - outline: 2px solid #0000; -} -.outline { - outline-style: solid; -} -.outline-dashed { - outline-style: dashed; -} -.outline-4 { - outline-width: 4px; -} -.-outline-offset-2 { - outline-offset: -2px; -} -.outline-offset-2 { - outline-offset: 2px; -} -.outline-black { - outline-color: #000; -} -.ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-4 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-white { - --tw-ring-color: #fff; -} -.ring-offset-2 { - --tw-ring-offset-width: 2px; -} -.ring-offset-blue-300 { - --tw-ring-offset-color: #93c5fd; -} -.blur-md { - --tw-blur: blur(12px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.brightness-150 { - --tw-brightness: brightness(1.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.contrast-50 { - --tw-contrast: contrast(0.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.drop-shadow-md { - --tw-drop-shadow: drop-shadow(0 4px 3px #00000012) drop-shadow(0 2px 2px #0000000f); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.grayscale { - --tw-grayscale: grayscale(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.hue-rotate-60 { - --tw-hue-rotate: hue-rotate(60deg); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.invert { - --tw-invert: invert(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.saturate-200 { - --tw-saturate: saturate(2); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.sepia { - --tw-sepia: sepia(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter { - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter-none { - filter: none; -} -.backdrop-blur-lg { - --tw-backdrop-blur: blur(16px); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-brightness-50 { - --tw-backdrop-brightness: brightness(0.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-contrast-0 { - --tw-backdrop-contrast: contrast(0); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-grayscale { - --tw-backdrop-grayscale: grayscale(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-hue-rotate-90 { - --tw-backdrop-hue-rotate: hue-rotate(90deg); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-invert { - --tw-backdrop-invert: invert(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-opacity-75 { - --tw-backdrop-opacity: opacity(0.75); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-saturate-150 { - --tw-backdrop-saturate: saturate(1.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-sepia { - --tw-backdrop-sepia: sepia(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter { - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter-none { - backdrop-filter: none; -} -.transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.transition-all { - transition-property: all; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.delay-300 { - transition-delay: 0.3s; -} -.duration-200 { - transition-duration: 0.2s; -} -.ease-in-out { - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.will-change-scroll { - will-change: scroll-position; -} -.will-change-transform { - will-change: transform; -} -.content-none { - --tw-content: none; - content: var(--tw-content); -} diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index 53c2a4418..10cdac86d 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -1,133 +1,132 @@ import fs from 'fs' import path from 'path' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('basic usage', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
{ backdrop-saturate-150 backdrop-sepia " - >
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } + >
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './basic-usage.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './basic-usage.oxide.test.css'), 'utf8') - ) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './basic-usage.test.css'), 'utf8') + ) }) +}) - test('all plugins are executed that match a candidate', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - green: { - light: 'green', - }, +test('all plugins are executed that match a candidate', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + green: { + light: 'green', }, }, - corePlugins: { preflight: false }, + }, + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + .bg-green { + /* Empty on purpose */ } + ` - let input = css` - @tailwind utilities; - - .bg-green { - /* Empty on purpose */ - } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-green-light { - --tw-bg-opacity: 1; - background-color: rgb(0 128 0 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-green-light { - background-color: green; - } - `) - }) - }) - - test('per-plugin colors with the same key can differ when using a custom colors object', () => { - let config = { - content: [ - { - raw: html` -
This should be green text on red background.
- `, - }, - ], - theme: { - // colors & theme MUST be plain objects - // If they're functions here the test passes regardless - colors: { - theme: { - bg: 'red', - text: 'green', - }, - }, - extend: { - textColor: { - theme: { - DEFAULT: 'green', - }, - }, - backgroundColor: { - theme: { - DEFAULT: 'red', - }, - }, - }, - }, - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-theme { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - .text-theme { - --tw-text-opacity: 1; - color: rgb(0 128 0 / var(--tw-text-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-theme { - background-color: red; - } - .text-theme { - color: green; - } - `) - }) - }) - - test('default ring color can be a function', () => { - function color(variable) { - return function ({ opacityVariable, opacityValue }) { - if (opacityValue !== undefined) { - return `rgba(${variable}, ${opacityValue})` - } - if (opacityVariable !== undefined) { - return `rgba(${variable}, var(${opacityVariable}, 1))` - } - return `rgb(${variable})` - } - } - - let config = { - content: [ - { - raw: html`
`, - }, - ], - - theme: { - extend: { - ringColor: { - DEFAULT: color('var(--red)'), - }, - }, - }, - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: 'rgba(var(--red), 0.5)' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('falsy config values still work', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - inset: { - 0: 0, - }, - }, - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .inset-0 { - inset: 0; - } - `) - }) - }) - - it('shadows support values without a leading zero', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - boxShadow: { - one: '0.5rem 0.5rem 0.5rem #0005', - two: '.5rem .5rem .5rem #0005', - }, - }, - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .shadow-one, - .shadow-two { - --tw-shadow: 0.5rem 0.5rem 0.5rem #0005; - --tw-shadow-colored: 0.5rem 0.5rem 0.5rem var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - it('can scan extremely long classes without crashing', () => { - let val = 'cols-' + '-a'.repeat(65536) - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css``) - }) - }) - - it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => { - let config = { - content: [{ raw: html`underline focus:*` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - - * { - color: red; - } - - .combined, - * { - text-align: center; - } - - @layer base { - * { - color: blue; - } - - .combined, - * { - color: red; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - * { - color: #00f; - } - .combined, - * { - color: red; - } - ${defaults} - .underline { - text-decoration-line: underline; - } - * { - color: red; - } - .combined, - * { - text-align: center; - } - `) - }) - }) - - it('can parse box shadows with variables', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - boxShadow: { - lg: 'var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0)', - }, - }, - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .shadow-lg { - --tw-shadow: var(--a, 0 35px 60px -15px #000), 0 0 1px #000; - --tw-shadow-colored: 0 35px 60px -15px var(--tw-shadow-color), - 0 0 1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - it('should generate styles using :not(.unknown-class) even if `.unknown-class` does not exist', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind components; - - @layer components { - div:not(.unknown-class) { - color: red; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - div:not(.unknown-class) { - color: red; - } - `) - }) - }) - - it('supports multiple backgrounds as arbitrary values even if only some are quoted', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[url\(\'\/images\/one-two-three\.png\'\)\,linear-gradient\(to_right\,_\#eeeeee\,_\#000000\)\] { - background-image: url('/images/one-two-three.png'), linear-gradient(to right, #eee, #000); - } - `) - }) - }) - - it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (1)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f680' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (2)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: 0.75, - }, - }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f6bf' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (1)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f', - }, - }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f80' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (2)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f00', - }, - }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f80' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (1)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f67f' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (2)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: 0.75, - }, - }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#3b82f67f' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (1)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f', - }, - }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (2)', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringColor: { - DEFAULT: '#ff7f7f00', - }, - }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults({ defaultRingColor: '#ff7f7f00' })} - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - `) - }) - }) - - it('A bare ring-opacity utility is not supported when not using respectDefaultRingColorOpacity', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: '0.33', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css``) - }) - }) - - test('A bare ring-opacity utility is supported when using respectDefaultRingColorOpacity', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - theme: { - ringOpacity: { - DEFAULT: '0.33', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .ring-opacity { - --tw-ring-opacity: 0.33; - } - `) - // The opacity plugins are disabled by default in the `oxide` engine - oxide.expect(result.css).toMatchFormattedCss(css``) - }) - }) - - it('Ring color utilities are generated when using respectDefaultRingColorOpacity', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .ring-blue-500 { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .ring-blue-500 { - --tw-ring-color: #3b82f6; - } - `) - }) - }) - - oxide.test.todo('should not crash when group names contain special characters') - stable.test('should not crash when group names contain special characters', () => { - let config = { - future: { respectDefaultRingColorOpacity: true }, - content: [ - { - raw: '
', - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .group\/\$\{id\}:hover .group-hover\/\$\{id\}\:visible { - visibility: visible; - } - `) - }) - }) - - it('should not crash when matching variants where utility classes are doubled up', () => { - let config = { - content: [ - { - raw: '
', - }, - ], - } - - let input = css` - @tailwind utilities; - @layer utilities { - .foo.foo { - text-decoration-line: underline; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .hover\:foo:hover.hover\:foo:hover { - text-decoration-line: underline; - } - `) - }) - }) - - test('detects quoted arbitrary values containing a slash', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - oxide.expect(result.css).toMatchFormattedCss(css` - .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { - display: none; - } - `) - - stable.expect(result.css).toMatchFormattedCss(css` - .hidden, - .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { - display: none; - } - `) - }) - - test('handled quoted arbitrary values containing escaped spaces', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - oxide.expect(result.css).toMatchFormattedCss(css` - .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { - display: none; - } - `) - - stable.expect(result.css).toMatchFormattedCss(css` - .hidden, - .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { - display: none; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-green-light { + --tw-bg-opacity: 1; + background-color: rgb(0 128 0 / var(--tw-bg-opacity)); } `) }) }) + +test('per-plugin colors with the same key can differ when using a custom colors object', () => { + let config = { + content: [ + { + raw: html` +
This should be green text on red background.
+ `, + }, + ], + theme: { + // colors & theme MUST be plain objects + // If they're functions here the test passes regardless + colors: { + theme: { + bg: 'red', + text: 'green', + }, + }, + extend: { + textColor: { + theme: { + DEFAULT: 'green', + }, + }, + backgroundColor: { + theme: { + DEFAULT: 'red', + }, + }, + }, + }, + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-theme { + --tw-bg-opacity: 1; + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); + } + .text-theme { + --tw-text-opacity: 1; + color: rgb(0 128 0 / var(--tw-text-opacity)); + } + `) + }) +}) + +test('default ring color can be a function', () => { + function color(variable) { + return function ({ opacityVariable, opacityValue }) { + if (opacityValue !== undefined) { + return `rgba(${variable}, ${opacityValue})` + } + if (opacityVariable !== undefined) { + return `rgba(${variable}, var(${opacityVariable}, 1))` + } + return `rgb(${variable})` + } + } + + let config = { + content: [ + { + raw: html`
`, + }, + ], + + theme: { + extend: { + ringColor: { + DEFAULT: color('var(--red)'), + }, + }, + }, + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: 'rgba(var(--red), 0.5)' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('falsy config values still work', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + inset: { + 0: 0, + }, + }, + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .inset-0 { + inset: 0; + } + `) + }) +}) + +it('shadows support values without a leading zero', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + boxShadow: { + one: '0.5rem 0.5rem 0.5rem #0005', + two: '.5rem .5rem .5rem #0005', + }, + }, + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .shadow-one, + .shadow-two { + --tw-shadow: 0.5rem 0.5rem 0.5rem #0005; + --tw-shadow-colored: 0.5rem 0.5rem 0.5rem var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +it('can scan extremely long classes without crashing', () => { + let val = 'cols-' + '-a'.repeat(65536) + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) + }) +}) + +it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => { + let config = { + content: [{ raw: html`underline focus:*` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + * { + color: red; + } + + .combined, + * { + text-align: center; + } + + @layer base { + * { + color: blue; + } + + .combined, + * { + color: red; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + * { + color: #00f; + } + .combined, + * { + color: red; + } + ${defaults} + .underline { + text-decoration-line: underline; + } + * { + color: red; + } + .combined, + * { + text-align: center; + } + `) + }) +}) + +it('can parse box shadows with variables', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + boxShadow: { + lg: 'var(--a, 0 35px 60px -15px rgba(0, 0, 0)), 0 0 1px rgb(0, 0, 0)', + }, + }, + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .shadow-lg { + --tw-shadow: var(--a, 0 35px 60px -15px #000), 0 0 1px #000; + --tw-shadow-colored: 0 35px 60px -15px var(--tw-shadow-color), + 0 0 1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +it('should generate styles using :not(.unknown-class) even if `.unknown-class` does not exist', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind components; + + @layer components { + div:not(.unknown-class) { + color: red; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + div:not(.unknown-class) { + color: red; + } + `) + }) +}) + +it('supports multiple backgrounds as arbitrary values even if only some are quoted', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[url\(\'\/images\/one-two-three\.png\'\)\,linear-gradient\(to_right\,_\#eeeeee\,_\#000000\)\] { + background-image: url('/images/one-two-three.png'), linear-gradient(to right, #eee, #000); + } + `) + }) +}) + +it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (1)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f680' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('The "default" ring opacity is used by the default ring color when not using respectDefaultRingColorOpacity (2)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: 0.75, + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f6bf' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (1)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f80' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color uses the "default" opacity when not using respectDefaultRingColorOpacity (2)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f00', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f80' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (1)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f67f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('The "default" ring color ignores the default opacity when using respectDefaultRingColorOpacity (2)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: 0.75, + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#3b82f67f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (1)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('Customizing the default ring color preserves its opacity when using respectDefaultRingColorOpacity (2)', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringColor: { + DEFAULT: '#ff7f7f00', + }, + }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults({ defaultRingColor: '#ff7f7f00' })} + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + `) + }) +}) + +it('A bare ring-opacity utility is not supported when not using respectDefaultRingColorOpacity', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: '0.33', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) + }) +}) + +test('A bare ring-opacity utility is supported when using respectDefaultRingColorOpacity', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + theme: { + ringOpacity: { + DEFAULT: '0.33', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .ring-opacity { + --tw-ring-opacity: 0.33; + } + `) + }) +}) + +it('Ring color utilities are generated when using respectDefaultRingColorOpacity', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .ring { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + .ring-blue-500 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); + } + `) + }) +}) + +test('should not crash when group names contain special characters', () => { + let config = { + future: { respectDefaultRingColorOpacity: true }, + content: [ + { + raw: '
', + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group\/\$\{id\}:hover .group-hover\/\$\{id\}\:visible { + visibility: visible; + } + `) + }) +}) + +it('should not crash when matching variants where utility classes are doubled up', () => { + let config = { + content: [ + { + raw: '
', + }, + ], + } + + let input = css` + @tailwind utilities; + @layer utilities { + .foo.foo { + text-decoration-line: underline; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .hover\:foo:hover.hover\:foo:hover { + text-decoration-line: underline; + } + `) + }) +}) + +test('detects quoted arbitrary values containing a slash', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .hidden, + .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { + display: none; + } + `) +}) + +test('handled quoted arbitrary values containing escaped spaces', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .hidden, + .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { + display: none; + } + `) +}) diff --git a/tests/blocklist.test.js b/tests/blocklist.test.js index 3642aa376..e9915350f 100644 --- a/tests/blocklist.test.js +++ b/tests/blocklist.test.js @@ -1,126 +1,107 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('can block classes matched literally', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - blocklist: ['font', 'uppercase', 'hover:text-sm', 'bg-red-500/50', 'my-custom-class'], +it('can block classes matched literally', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + blocklist: ['font', 'uppercase', 'hover:text-sm', 'bg-red-500/50', 'my-custom-class'], + } + + let input = css` + @tailwind utilities; + .my-custom-class { + color: red; } + ` - let input = css` - @tailwind utilities; + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } .my-custom-class { color: red; } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; + @media (min-width: 640px) { + .sm\:hover\:text-sm:hover { + font-size: 0.875rem; + line-height: 1.25rem; } - .my-custom-class { - color: red; - } - @media (min-width: 640px) { - .sm\:hover\:text-sm:hover { - font-size: 0.875rem; - line-height: 1.25rem; - } - } - `) - }) - }) - - it('can block classes inside @layer', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - blocklist: ['my-custom-class'], - } - - let input = css` - @tailwind utilities; - @layer utilities { - .my-custom-class { - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - `) - }) - }) - - it('blocklists do NOT support regexes', async () => { - let config = { - content: [{ raw: html`
` }], - blocklist: [/^bg-\[[^]+\]$/], - } - - let result = await run('@tailwind utilities', config) - - stable.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#f00d1e\] { - --tw-bg-opacity: 1; - background-color: rgb(240 13 30 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; } `) - - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-\[\#f00d1e\] { - background-color: #f00d1e; - } - .font-bold { - font-weight: 700; - } - `) - - expect().toHaveBeenWarnedWith(['blocklist-invalid']) - }) - - it('can block classes generated by the safelist', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [{ pattern: /^bg-red-(400|500)$/ }], - blocklist: ['bg-red-500'], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-400 { - --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); - } - .font-bold { - font-weight: 700; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-400 { - background-color: #f87171; - } - .font-bold { - font-weight: 700; - } - `) - }) + }) +}) + +it('can block classes inside @layer', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + blocklist: ['my-custom-class'], + } + + let input = css` + @tailwind utilities; + @layer utilities { + .my-custom-class { + color: red; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + `) + }) +}) + +it('blocklists do NOT support regexes', async () => { + let config = { + content: [{ raw: html`
` }], + blocklist: [/^bg-\[[^]+\]$/], + } + + let result = await run('@tailwind utilities', config) + + expect(result.css).toMatchFormattedCss(css` + .bg-\[\#f00d1e\] { + --tw-bg-opacity: 1; + background-color: rgb(240 13 30 / var(--tw-bg-opacity)); + } + .font-bold { + font-weight: 700; + } + `) + + expect().toHaveBeenWarnedWith(['blocklist-invalid']) +}) + +it('can block classes generated by the safelist', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [{ pattern: /^bg-red-(400|500)$/ }], + blocklist: ['bg-red-500'], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-400 { + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + } + .font-bold { + font-weight: 700; + } + `) }) }) diff --git a/tests/collapse-adjacent-rules.test.js b/tests/collapse-adjacent-rules.test.js index 4dbaab769..69c471686 100644 --- a/tests/collapse-adjacent-rules.test.js +++ b/tests/collapse-adjacent-rules.test.js @@ -1,114 +1,119 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('collapse adjacent rules', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [ - function ({ addVariant }) { - addVariant('foo-bar', '@supports (foo: bar)') - }, - ], +test('collapse adjacent rules', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [ + function ({ addVariant }) { + addVariant('foo-bar', '@supports (foo: bar)') + }, + ], + } + + let input = css` + @tailwind base; + @font-face { + font-family: 'Inter'; + src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); } - - let input = css` - @tailwind base; + @font-face { + font-family: 'Gilroy'; + src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); + } + @page { + margin: 1cm; + } + @tailwind components; + @tailwind utilities; + @layer base { @font-face { - font-family: 'Inter'; + font-family: 'Poppins'; + src: url('/fonts/Poppins.woff2') format('woff2'), url('/fonts/Poppins.woff') format('woff'); + } + @font-face { + font-family: 'Proxima Nova'; + src: url('/fonts/ProximaNova.woff2') format('woff2'), + url('/fonts/ProximaNova.woff') format('woff'); + } + } + .foo, + .bar { + color: black; + } + .foo, + .bar { + font-weight: 700; + } + .some-apply-thing { + @apply foo-bar:md:text-black foo-bar:md:font-bold foo-bar:text-black foo-bar:font-bold md:font-bold md:text-black; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @font-face { + font-family: Poppins; + src: url('/fonts/Poppins.woff2') format('woff2'), url('/fonts/Poppins.woff') format('woff'); + } + @font-face { + font-family: Proxima Nova; + src: url('/fonts/ProximaNova.woff2') format('woff2'), + url('/fonts/ProximaNova.woff') format('woff'); + } + ${defaults} + @font-face { + font-family: Inter; src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); } @font-face { - font-family: 'Gilroy'; + font-family: Gilroy; src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); } @page { margin: 1cm; } - @tailwind components; - @tailwind utilities; - @layer base { - @font-face { - font-family: 'Poppins'; - src: url('/fonts/Poppins.woff2') format('woff2'), - url('/fonts/Poppins.woff') format('woff'); - } - @font-face { - font-family: 'Proxima Nova'; - src: url('/fonts/ProximaNova.woff2') format('woff2'), - url('/fonts/ProximaNova.woff') format('woff'); - } - } - .foo, - .bar { - color: black; - } - .foo, - .bar { + .font-bold { font-weight: 700; } - .some-apply-thing { - @apply foo-bar:md:text-black foo-bar:md:font-bold foo-bar:text-black foo-bar:font-bold md:font-bold md:text-black; + .foo, + .bar { + color: #000; + font-weight: 700; } - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @font-face { - font-family: Poppins; - src: url('/fonts/Poppins.woff2') format('woff2'), - url('/fonts/Poppins.woff') format('woff'); - } - @font-face { - font-family: Proxima Nova; - src: url('/fonts/ProximaNova.woff2') format('woff2'), - url('/fonts/ProximaNova.woff') format('woff'); - } - ${defaults} - @font-face { - font-family: Inter; - src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); - } - @font-face { - font-family: Gilroy; - src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); - } - @page { - margin: 1cm; - } - .font-bold { + @supports (foo: bar) { + .some-apply-thing { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); font-weight: 700; } - .foo, - .bar { - color: #000; + } + @media (min-width: 768px) { + .some-apply-thing { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); font-weight: 700; } - @supports (foo: bar) { - .some-apply-thing { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity)); - font-weight: 700; - } - } + } + @supports (foo: bar) { @media (min-width: 768px) { .some-apply-thing { --tw-text-opacity: 1; @@ -116,134 +121,49 @@ crosscheck(({ stable, oxide }) => { font-weight: 700; } } - @supports (foo: bar) { - @media (min-width: 768px) { - .some-apply-thing { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity)); - font-weight: 700; - } - } + } + @media (min-width: 640px) { + .sm\:text-center { + text-align: center; } - @media (min-width: 640px) { - .sm\:text-center { - text-align: center; - } - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:font-bold { - font-weight: 700; - } - } - @media (min-width: 1024px) { - .lg\:text-center { - text-align: center; - } - .lg\:font-bold { - font-weight: 700; - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @font-face { - font-family: Poppins; - src: url('/fonts/Poppins.woff2') format('woff2'), - url('/fonts/Poppins.woff') format('woff'); - } - @font-face { - font-family: Proxima Nova; - src: url('/fonts/ProximaNova.woff2') format('woff2'), - url('/fonts/ProximaNova.woff') format('woff'); - } - ${defaults} - @font-face { - font-family: Inter; - src: url('/fonts/Inter.woff2') format('woff2'), url('/fonts/Inter.woff') format('woff'); - } - @font-face { - font-family: Gilroy; - src: url('/fonts/Gilroy.woff2') format('woff2'), url('/fonts/Gilroy.woff') format('woff'); - } - @page { - margin: 1cm; - } - .font-bold { + .sm\:font-bold { font-weight: 700; } - .foo, - .bar { - color: #000; + } + @media (min-width: 768px) { + .md\:text-center { + text-align: center; + } + .md\:font-bold { font-weight: 700; } - @supports (foo: bar) { - .some-apply-thing { - color: #000; - font-weight: 700; - } + } + @media (min-width: 1024px) { + .lg\:text-center { + text-align: center; } - @media (min-width: 768px) { - .some-apply-thing { - color: #000; - font-weight: 700; - } + .lg\:font-bold { + font-weight: 700; } - @supports (foo: bar) { - @media (min-width: 768px) { - .some-apply-thing { - color: #000; - font-weight: 700; - } - } - } - @media (min-width: 640px) { - .sm\:text-center { - text-align: center; - } - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:font-bold { - font-weight: 700; - } - } - @media (min-width: 1024px) { - .lg\:text-center { - text-align: center; - } - .lg\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - test('duplicate url imports does not break rule collapsing', () => { - let config = { - content: [{ raw: html`` }], - corePlugins: { preflight: false }, - } - - let input = css` - @import url('https://example.com'); - @import url('https://example.com'); - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @import 'https://example.com'; - `) - }) + } + `) + }) +}) + +test('duplicate url imports does not break rule collapsing', () => { + let config = { + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @import url('https://example.com'); + @import url('https://example.com'); + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @import 'https://example.com'; + `) }) }) diff --git a/tests/collapse-duplicate-declarations.test.js b/tests/collapse-duplicate-declarations.test.js index 128eb9bef..dc8834b74 100644 --- a/tests/collapse-duplicate-declarations.test.js +++ b/tests/collapse-duplicate-declarations.test.js @@ -1,177 +1,175 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - it('should collapse duplicate declarations with the same units (px)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } +it('should collapse duplicate declarations with the same units (px)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } - let input = css` - @tailwind utilities; + let input = css` + @tailwind utilities; - @layer utilities { - .example { - height: 100px; - height: 200px; - } + @layer utilities { + .example { + height: 100px; + height: 200px; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - height: 200px; - } - `) - }) - }) - - it('should collapse duplicate declarations with the same units (no unit)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], } + ` - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - line-height: 3; - line-height: 2; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + height: 200px; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - line-height: 2; - } - `) - }) - }) - - it('should not collapse duplicate declarations with the different units', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - height: 100px; - height: 50%; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - height: 100px; - height: 50%; - } - `) - }) - }) - - it('should collapse the duplicate declarations with the same unit, but leave the ones with different units', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - height: 100px; - height: 50%; - height: 20vh; - height: 200px; - height: 100%; - height: 30vh; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - height: 200px; - height: 100%; - height: 30vh; - } - `) - }) - }) - - it('should collapse the duplicate declarations with the exact same value', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .example { - height: var(--value); - color: blue; - height: var(--value); - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .example { - color: #00f; - height: var(--value); - } - `) - }) - }) - - it('should work on a real world example', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .h-available { - height: 100%; - height: 100vh; - height: -webkit-fill-available; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .h-available { - height: 100%; - height: 100vh; - height: -webkit-fill-available; - } - `) - }) + `) + }) +}) + +it('should collapse duplicate declarations with the same units (no unit)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + line-height: 3; + line-height: 2; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + line-height: 2; + } + `) + }) +}) + +it('should not collapse duplicate declarations with the different units', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + height: 100px; + height: 50%; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + height: 100px; + height: 50%; + } + `) + }) +}) + +it('should collapse the duplicate declarations with the same unit, but leave the ones with different units', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + height: 100px; + height: 50%; + height: 20vh; + height: 200px; + height: 100%; + height: 30vh; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + height: 200px; + height: 100%; + height: 30vh; + } + `) + }) +}) + +it('should collapse the duplicate declarations with the exact same value', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .example { + height: var(--value); + color: blue; + height: var(--value); + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .example { + color: #00f; + height: var(--value); + } + `) + }) +}) + +it('should work on a real world example', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .h-available { + height: 100%; + height: 100vh; + height: -webkit-fill-available; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .h-available { + height: 100%; + height: 100vh; + height: -webkit-fill-available; + } + `) }) }) diff --git a/tests/color-opacity-modifiers.test.js b/tests/color-opacity-modifiers.test.js index 8da4d38c2..a4600a495 100644 --- a/tests/color-opacity-modifiers.test.js +++ b/tests/color-opacity-modifiers.test.js @@ -1,264 +1,234 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('basic color opacity modifier', async () => { - let config = { - content: [{ raw: html`
` }], - } +test('basic color opacity modifier', async () => { + let config = { + content: [{ raw: html`
` }], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/50 { - background-color: #ef444480; - } - `) - }) - }) - - test('colors with slashes are matched first', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - extend: { - colors: { - 'red-500/50': '#ff0000', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/50 { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/50 { - background-color: red; - } - `) - }) - }) - - test('arbitrary color opacity modifier', async () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-red-500\/\[var\(--opacity\)\] { - background-color: rgb(239 68 68 / var(--opacity)); - } - `) - }) - }) - - test('missing alpha generates nothing', async () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(``) - }) - }) - - test('arbitrary color with opacity from scale', async () => { - let config = { - content: [{ raw: 'bg-[wheat]/50' }], - theme: {}, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[wheat\]\/50 { - background-color: #f5deb380; - } - `) - }) - }) - - test('arbitrary color with arbitrary opacity', async () => { - let config = { - content: [{ raw: 'bg-[#bada55]/[0.2]' }], - theme: {}, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[\#bada55\]\/\[0\.2\] { - background-color: #bada5533; - } - `) - }) - }) - - test('undefined theme color with opacity from scale', async () => { - let config = { - content: [{ raw: 'bg-garbage/50' }], - theme: {}, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(``) - }) - }) - - test('values not in the opacity config are ignored', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - opacity: { - 0: '0', - 25: '0.25', - 5: '0.5', - 75: '0.75', - 100: '1', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(``) - }) - }) - - test('function colors are supported', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - blue: ({ opacityValue }) => { - return `rgba(var(--colors-blue), ${opacityValue})` - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-blue\/50 { - background-color: rgba(var(--colors-blue), 0.5); - } - `) - }) - }) - - test('utilities that support any type are supported', async () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - theme: { - extend: { - fill: (theme) => theme('colors'), - }, - }, - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .from-red-500\/50 { - --tw-gradient-from: #ef444480 var(--tw-gradient-from-position); - --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .fill-red-500\/25 { - fill: #ef444440; - } - .placeholder-red-500\/75::placeholder { - color: #ef4444bf; - } - `) - }) - }) - - test('opacity modifier in combination with partial custom properties', async () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\] { - --tw-bg-opacity: 1; - background-color: hsl(123 50% var(--foo) / var(--tw-bg-opacity)); - } - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\]\/50 { - background-color: hsl(123 50% var(--foo) / 0.5); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\] { - --tw-bg-opacity: 1; - background-color: hsl(123 var(--foo) 50% / var(--tw-bg-opacity)); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\]\/50 { - background-color: hsl(123 var(--foo) 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\] { - --tw-bg-opacity: 1; - background-color: hsl(var(--foo) 50% 50% / var(--tw-bg-opacity)); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\]\/50 { - background-color: hsl(var(--foo) 50% 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,var\(--bar\)\,var\(--baz\)\)\]\/50 { - background-color: hsl(var(--foo) var(--bar) var(--baz) / 0.5); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\] { - background-color: hsl(123, 50%, var(--foo)); - } - .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\]\/50 { - background-color: hsl(123 50% var(--foo) / 0.5); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\] { - background-color: hsl(123, var(--foo), 50%); - } - .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\]\/50 { - background-color: hsl(123 var(--foo) 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\] { - background-color: hsl(var(--foo), 50%, 50%); - } - .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\]\/50 { - background-color: hsl(var(--foo) 50% 50% / 0.5); - } - .bg-\[hsl\(var\(--foo\)\,var\(--bar\)\,var\(--baz\)\)\]\/50 { - background-color: hsl(var(--foo) var(--bar) var(--baz) / 0.5); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/50 { + background-color: #ef444480; + } + `) + }) +}) + +test('colors with slashes are matched first', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + extend: { + colors: { + 'red-500/50': '#ff0000', + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/50 { + --tw-bg-opacity: 1; + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); + } + `) + }) +}) + +test('arbitrary color opacity modifier', async () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-500\/\[var\(--opacity\)\] { + background-color: rgb(239 68 68 / var(--opacity)); + } + `) + }) +}) + +test('missing alpha generates nothing', async () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) + +test('arbitrary color with opacity from scale', async () => { + let config = { + content: [{ raw: 'bg-[wheat]/50' }], + theme: {}, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[wheat\]\/50 { + background-color: #f5deb380; + } + `) + }) +}) + +test('arbitrary color with arbitrary opacity', async () => { + let config = { + content: [{ raw: 'bg-[#bada55]/[0.2]' }], + theme: {}, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[\#bada55\]\/\[0\.2\] { + background-color: #bada5533; + } + `) + }) +}) + +test('undefined theme color with opacity from scale', async () => { + let config = { + content: [{ raw: 'bg-garbage/50' }], + theme: {}, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) + +test('values not in the opacity config are ignored', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + opacity: { + 0: '0', + 25: '0.25', + 5: '0.5', + 75: '0.75', + 100: '1', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(``) + }) +}) + +test('function colors are supported', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + blue: ({ opacityValue }) => { + return `rgba(var(--colors-blue), ${opacityValue})` + }, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-blue\/50 { + background-color: rgba(var(--colors-blue), 0.5); + } + `) + }) +}) + +test('utilities that support any type are supported', async () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + theme: { + extend: { + fill: (theme) => theme('colors'), + }, + }, + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .from-red-500\/50 { + --tw-gradient-from: #ef444480 var(--tw-gradient-from-position); + --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .fill-red-500\/25 { + fill: #ef444440; + } + .placeholder-red-500\/75::placeholder { + color: #ef4444bf; + } + `) + }) +}) + +test('opacity modifier in combination with partial custom properties', async () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\] { + --tw-bg-opacity: 1; + background-color: hsl(123 50% var(--foo) / var(--tw-bg-opacity)); + } + .bg-\[hsl\(123\,50\%\,var\(--foo\)\)\]\/50 { + background-color: hsl(123 50% var(--foo) / 0.5); + } + .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\] { + --tw-bg-opacity: 1; + background-color: hsl(123 var(--foo) 50% / var(--tw-bg-opacity)); + } + .bg-\[hsl\(123\,var\(--foo\)\,50\%\)\]\/50 { + background-color: hsl(123 var(--foo) 50% / 0.5); + } + .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\] { + --tw-bg-opacity: 1; + background-color: hsl(var(--foo) 50% 50% / var(--tw-bg-opacity)); + } + .bg-\[hsl\(var\(--foo\)\,50\%\,50\%\)\]\/50 { + background-color: hsl(var(--foo) 50% 50% / 0.5); + } + .bg-\[hsl\(var\(--foo\)\,var\(--bar\)\,var\(--baz\)\)\]\/50 { + background-color: hsl(var(--foo) var(--bar) var(--baz) / 0.5); + } + `) }) }) diff --git a/tests/color.test.js b/tests/color.test.js index be1d85924..659a2d045 100644 --- a/tests/color.test.js +++ b/tests/color.test.js @@ -1,96 +1,93 @@ import { parseColor, formatColor } from '../src/util/color' -import { crosscheck } from './util/run' -crosscheck(() => { - describe('parseColor', () => { - it.each` - color | output - ${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} - ${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} - ${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} - ${'#0088cc99'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} - ${'#08c9'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} - ${'rgb(0, 30, 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} - ${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgba', color: ['0', '30', '60'], alpha: '0.5' }} - ${'rgb(0 30 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} - ${'rgb(0 30 60 / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }} - ${'rgb(var(--foo), 30, 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} - ${'rgb(0, var(--foo), 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} - ${'rgb(0, 30, var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} - ${'rgb(0, 30, var(--foo), 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} - ${'rgb(var(--foo), 30, var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} - ${'rgb(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'rgb(var(--foo) 30 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} - ${'rgb(0 var(--foo) 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} - ${'rgb(0 30 var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} - ${'rgb(0 30 var(--foo) / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} - ${'rgb(var(--foo) 30 var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} - ${'rgb(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'hsl(0, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} - ${'hsl(0deg, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} - ${'hsl(0rad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} - ${'hsl(0grad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} - ${'hsl(0turn, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} - ${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0deg, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0deg', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0rad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0rad', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0grad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0grad', '30%', '60%'], alpha: '0.5' }} - ${'hsla(0turn, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0turn', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0 30% 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} - ${'hsl(0deg 30% 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} - ${'hsl(0rad 30% 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} - ${'hsl(0grad 30% 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} - ${'hsl(0turn 30% 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} - ${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0deg 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0rad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0grad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }} - ${'hsl(0turn 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }} - ${'hsl(var(--foo), 30%, 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} - ${'hsl(0, var(--foo), 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} - ${'hsl(0, 30%, var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} - ${'hsl(0, 30%, var(--foo), 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} - ${'hsl(var(--foo), 30%, var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} - ${'hsl(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'hsl(var(--foo) 30% 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} - ${'hsl(0 var(--foo) 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} - ${'hsl(0 30% var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} - ${'hsl(0 30% var(--foo) / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} - ${'hsl(var(--foo) 30% var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} - ${'hsl(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} - ${'rgba(var(--foo), 0.1)'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: '0.1' }} - ${'rgba(var(--foo), var(--alpha))'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: 'var(--alpha)' }} - ${'hsla(var(--foo), 0.1)'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: '0.1' }} - ${'hsla(var(--foo), var(--alpha))'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: 'var(--alpha)' }} - ${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }} - `('should parse "$color" to the correct value', ({ color, output }) => { - expect(parseColor(color)).toEqual(output) - }) - - it.each` - color - ${'var(--my-color)'} - ${'currentColor'} - ${'inherit'} - ${'initial'} - ${'revert'} - ${'unset'} - `('should return `null` for unparseable color "$color"', ({ color }) => { - expect(parseColor(color)).toBe(null) - }) +describe('parseColor', () => { + it.each` + color | output + ${'black'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} + ${'#0088cc'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} + ${'#08c'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} + ${'#0088cc99'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} + ${'#08c9'} | ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} + ${'rgb(0, 30, 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} + ${'rgba(0, 30, 60, 0.5)'} | ${{ mode: 'rgba', color: ['0', '30', '60'], alpha: '0.5' }} + ${'rgb(0 30 60)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: undefined }} + ${'rgb(0 30 60 / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', '60'], alpha: '0.5' }} + ${'rgb(var(--foo), 30, 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} + ${'rgb(0, var(--foo), 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} + ${'rgb(0, 30, var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} + ${'rgb(0, 30, var(--foo), 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} + ${'rgb(var(--foo), 30, var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} + ${'rgb(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'rgb(var(--foo) 30 60)'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', '60'], alpha: undefined }} + ${'rgb(0 var(--foo) 60)'} | ${{ mode: 'rgb', color: ['0', 'var(--foo)', '60'], alpha: undefined }} + ${'rgb(0 30 var(--foo))'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: undefined }} + ${'rgb(0 30 var(--foo) / 0.5)'} | ${{ mode: 'rgb', color: ['0', '30', 'var(--foo)'], alpha: '0.5' }} + ${'rgb(var(--foo) 30 var(--bar))'} | ${{ mode: 'rgb', color: ['var(--foo)', '30', 'var(--bar)'], alpha: undefined }} + ${'rgb(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'rgb', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'hsl(0, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} + ${'hsl(0deg, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} + ${'hsl(0rad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} + ${'hsl(0grad, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} + ${'hsl(0turn, 30%, 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} + ${'hsla(0, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0deg, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0deg', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0rad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0rad', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0grad, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0grad', '30%', '60%'], alpha: '0.5' }} + ${'hsla(0turn, 30%, 60%, 0.5)'} | ${{ mode: 'hsla', color: ['0turn', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0 30% 60%)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: undefined }} + ${'hsl(0deg 30% 60%)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: undefined }} + ${'hsl(0rad 30% 60%)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: undefined }} + ${'hsl(0grad 30% 60%)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: undefined }} + ${'hsl(0turn 30% 60%)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: undefined }} + ${'hsl(0 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0deg 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0deg', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0rad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0rad', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0grad 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0grad', '30%', '60%'], alpha: '0.5' }} + ${'hsl(0turn 30% 60% / 0.5)'} | ${{ mode: 'hsl', color: ['0turn', '30%', '60%'], alpha: '0.5' }} + ${'hsl(var(--foo), 30%, 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} + ${'hsl(0, var(--foo), 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} + ${'hsl(0, 30%, var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} + ${'hsl(0, 30%, var(--foo), 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} + ${'hsl(var(--foo), 30%, var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} + ${'hsl(var(--foo), var(--bar), var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'hsl(var(--foo) 30% 60%)'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', '60%'], alpha: undefined }} + ${'hsl(0 var(--foo) 60%)'} | ${{ mode: 'hsl', color: ['0', 'var(--foo)', '60%'], alpha: undefined }} + ${'hsl(0 30% var(--foo))'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: undefined }} + ${'hsl(0 30% var(--foo) / 0.5)'} | ${{ mode: 'hsl', color: ['0', '30%', 'var(--foo)'], alpha: '0.5' }} + ${'hsl(var(--foo) 30% var(--bar))'} | ${{ mode: 'hsl', color: ['var(--foo)', '30%', 'var(--bar)'], alpha: undefined }} + ${'hsl(var(--foo) var(--bar) var(--baz))'} | ${{ mode: 'hsl', color: ['var(--foo)', 'var(--bar)', 'var(--baz)'], alpha: undefined }} + ${'rgba(var(--foo), 0.1)'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: '0.1' }} + ${'rgba(var(--foo), var(--alpha))'} | ${{ mode: 'rgba', color: ['var(--foo)'], alpha: 'var(--alpha)' }} + ${'hsla(var(--foo), 0.1)'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: '0.1' }} + ${'hsla(var(--foo), var(--alpha))'} | ${{ mode: 'hsla', color: ['var(--foo)'], alpha: 'var(--alpha)' }} + ${'transparent'} | ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: '0' }} + `('should parse "$color" to the correct value', ({ color, output }) => { + expect(parseColor(color)).toEqual(output) }) - describe('formatColor', () => { - it.each` - color | output - ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} | ${'rgb(0 0 0)'} - ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} | ${'rgb(0 136 204)'} - ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} | ${'rgb(0 136 204 / 0.6)'} - ${{ mode: 'hsl', color: ['0', '0%', '0%'], alpha: undefined }} | ${'hsl(0 0% 0%)'} - ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: undefined }} | ${'hsl(0 136% 204%)'} - ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: '0.6' }} | ${'hsl(0 136% 204% / 0.6)'} - `('should format the color pieces into a proper "$output"', ({ color, output }) => { - expect(formatColor(color)).toEqual(output) - }) + it.each` + color + ${'var(--my-color)'} + ${'currentColor'} + ${'inherit'} + ${'initial'} + ${'revert'} + ${'unset'} + `('should return `null` for unparseable color "$color"', ({ color }) => { + expect(parseColor(color)).toBe(null) + }) +}) + +describe('formatColor', () => { + it.each` + color | output + ${{ mode: 'rgb', color: ['0', '0', '0'], alpha: undefined }} | ${'rgb(0 0 0)'} + ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: undefined }} | ${'rgb(0 136 204)'} + ${{ mode: 'rgb', color: ['0', '136', '204'], alpha: '0.6' }} | ${'rgb(0 136 204 / 0.6)'} + ${{ mode: 'hsl', color: ['0', '0%', '0%'], alpha: undefined }} | ${'hsl(0 0% 0%)'} + ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: undefined }} | ${'hsl(0 136% 204%)'} + ${{ mode: 'hsl', color: ['0', '136%', '204%'], alpha: '0.6' }} | ${'hsl(0 136% 204% / 0.6)'} + `('should format the color pieces into a proper "$output"', ({ color, output }) => { + expect(formatColor(color)).toEqual(output) }) }) diff --git a/tests/combined-selectors.test.js b/tests/combined-selectors.test.js index 51aa0a8ce..b3e8a333f 100644 --- a/tests/combined-selectors.test.js +++ b/tests/combined-selectors.test.js @@ -1,76 +1,74 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - it('should generate the partial selector, if only a partial is used (base layer)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should generate the partial selector, if only a partial is used (base layer)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; + let input = css` + @tailwind base; - @layer base { - :root { - font-weight: bold; - } - - /* --- */ - - :root, - .a { - color: black; - } + @layer base { + :root { + font-weight: bold; } - ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :root { - font-weight: bold; - } - :root, - .a { - color: #000; - } - ${defaults} - `) - }) - }) + /* --- */ - it('should generate the partial selector, if only a partial is used (utilities layer)', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - - @layer utilities { - :root { - font-weight: bold; - } - - /* --- */ - - :root, - .a { - color: black; - } + :root, + .a { + color: black; } - ` + } + ` - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :root { - font-weight: bold; - } - :root, - .a { - color: #000; - } - `) - }) + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + :root { + font-weight: bold; + } + :root, + .a { + color: #000; + } + ${defaults} + `) + }) +}) + +it('should generate the partial selector, if only a partial is used (utilities layer)', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + @layer utilities { + :root { + font-weight: bold; + } + + /* --- */ + + :root, + .a { + color: black; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + :root { + font-weight: bold; + } + :root, + .a { + color: #000; + } + `) }) }) diff --git a/tests/configurePlugins.test.js b/tests/configurePlugins.test.js index 367ab223f..490cddc03 100644 --- a/tests/configurePlugins.test.js +++ b/tests/configurePlugins.test.js @@ -1,28 +1,25 @@ import configurePlugins from '../src/util/configurePlugins' -import { crosscheck } from './util/run' -crosscheck(() => { - test('setting a plugin to false removes it', () => { - const plugins = ['fontSize', 'display', 'backgroundPosition'] +test('setting a plugin to false removes it', () => { + const plugins = ['fontSize', 'display', 'backgroundPosition'] - const configuredPlugins = configurePlugins({ display: false }, plugins) + const configuredPlugins = configurePlugins({ display: false }, plugins) - expect(configuredPlugins).toEqual(['fontSize', 'backgroundPosition']) - }) - - test('passing only false removes all plugins', () => { - const plugins = ['fontSize', 'display', 'backgroundPosition'] - - const configuredPlugins = configurePlugins(false, plugins) - - expect(configuredPlugins).toEqual([]) - }) - - test('passing an array safelists plugins', () => { - const plugins = ['fontSize', 'display', 'backgroundPosition'] - - const configuredPlugins = configurePlugins(['display'], plugins) - - expect(configuredPlugins).toEqual(['display']) - }) + expect(configuredPlugins).toEqual(['fontSize', 'backgroundPosition']) +}) + +test('passing only false removes all plugins', () => { + const plugins = ['fontSize', 'display', 'backgroundPosition'] + + const configuredPlugins = configurePlugins(false, plugins) + + expect(configuredPlugins).toEqual([]) +}) + +test('passing an array safelists plugins', () => { + const plugins = ['fontSize', 'display', 'backgroundPosition'] + + const configuredPlugins = configurePlugins(['display'], plugins) + + expect(configuredPlugins).toEqual(['display']) }) diff --git a/tests/containerPlugin.test.js b/tests/containerPlugin.test.js index 428a807d0..4b334e90c 100644 --- a/tests/containerPlugin.test.js +++ b/tests/containerPlugin.test.js @@ -1,347 +1,345 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({}) => { - test('options are not required', () => { - let config = { content: [{ raw: html`
` }] } +test('options are not required', () => { + let config = { content: [{ raw: html`
` }] } - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 640px) { .container { - width: 100%; + max-width: 640px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - `) - }) - }) - - test('screens can be passed explicitly', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['400px', '500px'], - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 768px) { .container { - width: 100%; + max-width: 768px; } - @media (min-width: 400px) { - .container { - max-width: 400px; - } - } - @media (min-width: 500px) { - .container { - max-width: 500px; - } - } - `) - }) - }) - - test('screens are ordered ascending by min-width', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['500px', '400px'], - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 1024px) { .container { - width: 100%; + max-width: 1024px; } - @media (min-width: 400px) { - .container { - max-width: 400px; - } - } - @media (min-width: 500px) { - .container { - max-width: 500px; - } - } - `) - }) - }) - - test('screens are deduplicated by min-width', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: { - sm: '576px', - md: '768px', - 'sm-only': { min: '576px', max: '767px' }, - }, - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 1280px) { .container { - width: 100%; + max-width: 1280px; } - @media (min-width: 576px) { - .container { - max-width: 576px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - `) - }) - }) - - test('the container can be centered by default', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - center: true, - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + } + @media (min-width: 1536px) { .container { - width: 100%; - margin-left: auto; - margin-right: auto; + max-width: 1536px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - `) - }) - }) - - test('horizontal padding can be included by default', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - padding: '2rem', - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .container { - width: 100%; - padding-left: 2rem; - padding-right: 2rem; - } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - `) - }) - }) - - test('responsive horizontal padding can be included by default', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - screens: { - sm: '576px', - md: { min: '768px' }, - lg: { 'min-width': '992px' }, - xl: { min: '1200px', max: '1600px' }, - }, - container: { - padding: { - DEFAULT: '1rem', - sm: '2rem', - lg: '4rem', - xl: '5rem', - }, - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .container { - width: 100%; - padding-left: 1rem; - padding-right: 1rem; - } - @media (min-width: 576px) { - .container { - max-width: 576px; - padding-left: 2rem; - padding-right: 2rem; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 992px) { - .container { - max-width: 992px; - padding-left: 4rem; - padding-right: 4rem; - } - } - @media (min-width: 1200px) { - .container { - max-width: 1200px; - padding-left: 5rem; - padding-right: 5rem; - } - } - `) - }) - }) - - test('setting all options at once', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['400px', '500px'], - center: true, - padding: '2rem', - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .container { - width: 100%; - margin-left: auto; - margin-right: auto; - padding-left: 2rem; - padding-right: 2rem; - } - @media (min-width: 400px) { - .container { - max-width: 400px; - } - } - @media (min-width: 500px) { - .container { - max-width: 500px; - } - } - `) - }) - }) - - test('container can use variants', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - container: { - screens: ['400px', '500px'], - }, - }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 1024px) { - .lg\:hover\:container:hover { - width: 100%; - } - @media (min-width: 400px) { - .lg\:hover\:container:hover { - max-width: 400px; - } - } - @media (min-width: 500px) { - .lg\:hover\:container:hover { - max-width: 500px; - } - } - } - `) - }) + } + `) + }) +}) + +test('screens can be passed explicitly', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['400px', '500px'], + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 400px) { + .container { + max-width: 400px; + } + } + @media (min-width: 500px) { + .container { + max-width: 500px; + } + } + `) + }) +}) + +test('screens are ordered ascending by min-width', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['500px', '400px'], + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 400px) { + .container { + max-width: 400px; + } + } + @media (min-width: 500px) { + .container { + max-width: 500px; + } + } + `) + }) +}) + +test('screens are deduplicated by min-width', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: { + sm: '576px', + md: '768px', + 'sm-only': { min: '576px', max: '767px' }, + }, + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + } + @media (min-width: 576px) { + .container { + max-width: 576px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + `) + }) +}) + +test('the container can be centered by default', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + center: true, + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + margin-left: auto; + margin-right: auto; + } + @media (min-width: 640px) { + .container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + `) + }) +}) + +test('horizontal padding can be included by default', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + padding: '2rem', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + padding-left: 2rem; + padding-right: 2rem; + } + @media (min-width: 640px) { + .container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + `) + }) +}) + +test('responsive horizontal padding can be included by default', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + screens: { + sm: '576px', + md: { min: '768px' }, + lg: { 'min-width': '992px' }, + xl: { min: '1200px', max: '1600px' }, + }, + container: { + padding: { + DEFAULT: '1rem', + sm: '2rem', + lg: '4rem', + xl: '5rem', + }, + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + padding-left: 1rem; + padding-right: 1rem; + } + @media (min-width: 576px) { + .container { + max-width: 576px; + padding-left: 2rem; + padding-right: 2rem; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 992px) { + .container { + max-width: 992px; + padding-left: 4rem; + padding-right: 4rem; + } + } + @media (min-width: 1200px) { + .container { + max-width: 1200px; + padding-left: 5rem; + padding-right: 5rem; + } + } + `) + }) +}) + +test('setting all options at once', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['400px', '500px'], + center: true, + padding: '2rem', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .container { + width: 100%; + margin-left: auto; + margin-right: auto; + padding-left: 2rem; + padding-right: 2rem; + } + @media (min-width: 400px) { + .container { + max-width: 400px; + } + } + @media (min-width: 500px) { + .container { + max-width: 500px; + } + } + `) + }) +}) + +test('container can use variants', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + container: { + screens: ['400px', '500px'], + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 1024px) { + .lg\:hover\:container:hover { + width: 100%; + } + @media (min-width: 400px) { + .lg\:hover\:container:hover { + max-width: 400px; + } + } + @media (min-width: 500px) { + .lg\:hover\:container:hover { + max-width: 500px; + } + } + } + `) }) }) diff --git a/tests/context-reuse.test.js b/tests/context-reuse.test.js index 4ead43fd4..7cd006cde 100644 --- a/tests/context-reuse.test.js +++ b/tests/context-reuse.test.js @@ -1,4 +1,4 @@ -import { crosscheck, css } from './util/run' +import { css } from './util/run' const fs = require('fs') const path = require('path') @@ -7,126 +7,122 @@ const tailwind = require('../src/index.js') const sharedState = require('../src/lib/sharedState.js') const configPath = path.resolve(__dirname, './context-reuse.tailwind.config.js') -crosscheck(({ stable, oxide }) => { - function run(input, config = {}, from = null) { - let { currentTestName } = expect.getState() +function run(input, config = {}, from = null) { + let { currentTestName } = expect.getState() - from = `${path.resolve(__filename)}?test=${currentTestName}&${from}` + from = `${path.resolve(__filename)}?test=${currentTestName}&${from}` - return postcss(tailwind(config)).process(input, { from }) + return postcss(tailwind(config)).process(input, { from }) +} + +beforeEach(async () => { + let config = { + content: [path.resolve(__dirname, './context-reuse.test.html')], + corePlugins: { preflight: false }, } - beforeEach(async () => { - let config = { - content: [path.resolve(__dirname, './context-reuse.test.html')], - corePlugins: { preflight: false }, + await fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`) +}) + +afterEach(async () => { + await fs.promises.unlink(configPath) +}) + +test('re-uses the context across multiple files with the same config', async () => { + let results = [ + await run(`@tailwind utilities;`, configPath, `id=1`), + + // Using @apply directives should still re-use the context + // They depend on the config but do not the other way around + await run(`body { @apply bg-blue-400; }`, configPath, `id=2`), + await run(`body { @apply text-red-400; }`, configPath, `id=3`), + await run(`body { @apply mb-4; }`, configPath, `id=4`), + ] + + let dependencies = results.map((result) => { + return result.messages + .filter((message) => message.type === 'dependency') + .map((message) => message.file) + }) + + // The content files don't have any utilities in them so this should be empty + expect(results[0].css).toMatchFormattedCss(css``) + + // However, @apply is being used so we want to verify that they're being inlined into the CSS rules + expect(results[1].css).toMatchFormattedCss(css` + body { + --tw-bg-opacity: 1; + background-color: rgb(96 165 250 / var(--tw-bg-opacity)); } + `) - await fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`) - }) + expect(results[2].css).toMatchFormattedCss(css` + body { + --tw-text-opacity: 1; + color: rgb(248 113 113 / var(--tw-text-opacity)); + } + `) - afterEach(async () => { - await fs.promises.unlink(configPath) - }) + expect(results[3].css).toMatchFormattedCss(css` + body { + margin-bottom: 1rem; + } + `) - oxide.test.todo('re-uses the context across multiple files with the same config') - stable.test('re-uses the context across multiple files with the same config', async () => { - let results = [ - await run(`@tailwind utilities;`, configPath, `id=1`), + // Files with @tailwind directives depends on the PostCSS tree, config, AND any content files + expect(dependencies[0]).toEqual([ + path.resolve(__dirname, 'context-reuse.test.html'), + path.resolve(__dirname, 'context-reuse.tailwind.config.js'), + ]) - // Using @apply directives should still re-use the context - // They depend on the config but do not the other way around - await run(`body { @apply bg-blue-400; }`, configPath, `id=2`), - await run(`body { @apply text-red-400; }`, configPath, `id=3`), - await run(`body { @apply mb-4; }`, configPath, `id=4`), - ] + // @apply depends only on the containing PostCSS tree *and* the config file but no content files + // as they cannot affect the outcome of the @apply directives + expect(dependencies[1]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - let dependencies = results.map((result) => { - return result.messages - .filter((message) => message.type === 'dependency') - .map((message) => message.file) - }) + expect(dependencies[2]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - // The content files don't have any utilities in them so this should be empty - expect(results[0].css).toMatchFormattedCss(css``) + expect(dependencies[3]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - // However, @apply is being used so we want to verify that they're being inlined into the CSS rules - expect(results[1].css).toMatchFormattedCss(css` - body { - --tw-bg-opacity: 1; - background-color: rgb(96 165 250 / var(--tw-bg-opacity)); - } - `) + // And none of this should have resulted in multiple contexts being created + expect(sharedState.contextSourcesMap.size).toBe(1) +}) - expect(results[2].css).toMatchFormattedCss(css` - body { - --tw-text-opacity: 1; - color: rgb(248 113 113 / var(--tw-text-opacity)); - } - `) +test('updates layers when any CSS containing @tailwind directives changes', async () => { + let result - expect(results[3].css).toMatchFormattedCss(css` - body { - margin-bottom: 1rem; - } - `) - - // Files with @tailwind directives depends on the PostCSS tree, config, AND any content files - expect(dependencies[0]).toEqual([ - path.resolve(__dirname, 'context-reuse.test.html'), - path.resolve(__dirname, 'context-reuse.tailwind.config.js'), - ]) - - // @apply depends only on the containing PostCSS tree *and* the config file but no content files - // as they cannot affect the outcome of the @apply directives - expect(dependencies[1]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - - expect(dependencies[2]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - - expect(dependencies[3]).toEqual([path.resolve(__dirname, 'context-reuse.tailwind.config.js')]) - - // And none of this should have resulted in multiple contexts being created - expect(sharedState.contextSourcesMap.size).toBe(1) - }) - - oxide.test.todo('updates layers when any CSS containing @tailwind directives changes') - stable.test('updates layers when any CSS containing @tailwind directives changes', async () => { - let result - - // Compile the initial version once - let input = css` - @tailwind utilities; - @layer utilities { - .custom-utility { - color: orange; - } - } - ` - - result = await run(input, configPath, `id=1`) - - expect(result.css).toMatchFormattedCss(css` - .only\:custom-utility:only-child { + // Compile the initial version once + let input = css` + @tailwind utilities; + @layer utilities { + .custom-utility { color: orange; } - `) + } + ` - // Save the file with a change - input = css` - @tailwind utilities; - @layer utilities { - .custom-utility { - color: blue; - } + result = await run(input, configPath, `id=1`) + + expect(result.css).toMatchFormattedCss(css` + .only\:custom-utility:only-child { + color: orange; + } + `) + + // Save the file with a change + input = css` + @tailwind utilities; + @layer utilities { + .custom-utility { + color: blue; } - ` + } + ` - result = await run(input, configPath, `id=1`) + result = await run(input, configPath, `id=1`) - expect(result.css).toMatchFormattedCss(css` - .only\:custom-utility:only-child { - color: #00f; - } - `) - }) + expect(result.css).toMatchFormattedCss(css` + .only\:custom-utility:only-child { + color: #00f; + } + `) }) diff --git a/tests/custom-extractors.test.js b/tests/custom-extractors.test.js index 089084e77..f5933b7a5 100644 --- a/tests/custom-extractors.test.js +++ b/tests/custom-extractors.test.js @@ -1,4 +1,4 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' function customExtractor(content) { let matches = content.match(/class="([^"]+)"/) @@ -21,117 +21,109 @@ let expected = css` } ` -crosscheck(({ stable, oxide }) => { - describe('modern', () => { - oxide.test.todo('extract.DEFAULT') - stable.test('extract.DEFAULT', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - extract: { - DEFAULT: customExtractor, - }, +describe('modern', () => { + test('extract.DEFAULT', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + extract: { + DEFAULT: customExtractor, }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) - }) - - oxide.test.todo('extract.{extension}') - stable.test('extract.{extension}', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - extract: { - html: customExtractor, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) - }) - - oxide.test.todo('extract function') - stable.test('extract function', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - extract: customExtractor, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) - }) - - oxide.test.todo('raw content with extension') - stable.test('raw content with extension', () => { - let config = { - content: { - files: [ - { - raw: sharedHtml, - extension: 'html', - }, - ], - extract: { - html: () => ['invisible'], - }, - }, - corePlugins: { preflight: false }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .invisible { - visibility: hidden; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) }) }) - describe('legacy', () => { - oxide.test.todo('defaultExtractor') - stable.test('defaultExtractor', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - options: { - defaultExtractor: customExtractor, - }, + test('extract.{extension}', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + extract: { + html: customExtractor, }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) }) + }) - oxide.test.todo('extractors array') - stable.test('extractors array', () => { - let config = { - content: { - files: [{ raw: sharedHtml }], - options: { - extractors: [ - { - extractor: customExtractor, - extensions: ['html'], - }, - ], + test('extract function', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + extract: customExtractor, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) + }) + }) + + test('raw content with extension', () => { + let config = { + content: { + files: [ + { + raw: sharedHtml, + extension: 'html', }, + ], + extract: { + html: () => ['invisible'], }, - } + }, + corePlugins: { preflight: false }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(expected) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .invisible { + visibility: hidden; + } + `) + }) + }) +}) + +describe('legacy', () => { + test('defaultExtractor', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + options: { + defaultExtractor: customExtractor, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) + }) + }) + + test('extractors array', () => { + let config = { + content: { + files: [{ raw: sharedHtml }], + options: { + extractors: [ + { + extractor: customExtractor, + extensions: ['html'], + }, + ], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(expected) }) }) }) diff --git a/tests/custom-plugins.test.js b/tests/custom-plugins.test.js index d91843199..0f45e9823 100644 --- a/tests/custom-plugins.test.js +++ b/tests/custom-plugins.test.js @@ -1,18 +1,1132 @@ import createPlugin from '../src/public/create-plugin' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('plugins can create utilities with object syntax', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities }) { +test('plugins can create utilities with object syntax', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-object-fill': { + 'object-fit': 'fill', + }, + '.custom-object-contain': { + 'object-fit': 'contain', + }, + '.custom-object-cover': { + 'object-fit': 'cover', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create utilities with arrays of objects', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities }) { + addUtilities([ + { + '.custom-object-fill': { + 'object-fit': 'fill', + }, + '.custom-object-contain': { + 'object-fit': 'contain', + }, + '.custom-object-cover': { + 'object-fit': 'cover', + }, + }, + ]) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create utilities with raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities, postcss }) { + addUtilities([ + postcss.rule({ selector: '.custom-object-fill' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'fill', + }), + ]), + postcss.rule({ selector: '.custom-object-contain' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'contain', + }), + ]), + postcss.rule({ selector: '.custom-object-cover' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'cover', + }), + ]), + ]) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create utilities with mixed object styles and PostCSS nodes', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addUtilities, postcss }) { + addUtilities([ + { + '.custom-object-fill': { + objectFit: 'fill', + }, + }, + postcss.rule({ selector: '.custom-object-contain' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'contain', + }), + ]), + postcss.rule({ selector: '.custom-object-cover' }).append([ + postcss.decl({ + prop: 'object-fit', + value: 'cover', + }), + ]), + ]) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) + }) +}) + +test('plugins can create components with object syntax', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + color: 'white', + padding: '.5rem 1rem', + borderRadius: '.25rem', + }, + '.btn-blue:hover': { + backgroundColor: 'darkblue', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + `) + }) +}) + +test('plugins can add base styles with object syntax', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addBase }) { + addBase({ + img: { + maxWidth: '100%', + }, + button: { + fontFamily: 'inherit', + }, + }) + }, + ], + corePlugins: { preflight: false }, + } + + return run('@tailwind base', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + img { + max-width: 100%; + } + button { + font-family: inherit; + } + ${defaults} + `) + }) +}) + +test('plugins can add base styles with raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addBase, postcss }) { + addBase([ + postcss.rule({ selector: 'img' }).append([ + postcss.decl({ + prop: 'max-width', + value: '100%', + }), + ]), + postcss.rule({ selector: 'button' }).append([ + postcss.decl({ + prop: 'font-family', + value: 'inherit', + }), + ]), + ]) + }, + ], + corePlugins: { preflight: false }, + } + + return run('@tailwind base', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + img { + max-width: 100%; + } + button { + font-family: inherit; + } + ${defaults} + `) + }) +}) + +test('plugins can create components with raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addComponents, postcss }) { + addComponents([ + postcss.rule({ selector: '.btn-blue' }).append([ + postcss.decl({ + prop: 'background-color', + value: 'blue', + }), + postcss.decl({ + prop: 'color', + value: 'white', + }), + postcss.decl({ + prop: 'padding', + value: '.5rem 1rem', + }), + postcss.decl({ + prop: 'border-radius', + value: '.25rem', + }), + ]), + postcss.rule({ selector: '.btn-blue:hover' }).append([ + postcss.decl({ + prop: 'background-color', + value: 'darkblue', + }), + ]), + ]) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + `) + }) +}) + +test('plugins can create components with mixed object styles and raw PostCSS nodes', () => { + let config = { + content: [ + { + raw: html``, + }, + ], + plugins: [ + function ({ addComponents, postcss }) { + addComponents([ + postcss.rule({ selector: '.btn-blue' }).append([ + postcss.decl({ + prop: 'background-color', + value: 'blue', + }), + postcss.decl({ + prop: 'color', + value: 'white', + }), + postcss.decl({ + prop: 'padding', + value: '.5rem 1rem', + }), + postcss.decl({ + prop: 'border-radius', + value: '.25rem', + }), + ]), + { + '.btn-blue:hover': { + backgroundColor: 'darkblue', + }, + }, + ]) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + `) + }) +}) + +test('plugins can create components with media queries with object syntax', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.custom-container': { + width: '100%', + }, + '@media (min-width: 100px)': { + '.custom-container': { + maxWidth: '100px', + }, + }, + '@media (min-width: 200px)': { + '.custom-container': { + maxWidth: '200px', + }, + }, + '@media (min-width: 300px)': { + '.custom-container': { + maxWidth: '300px', + }, + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-container { + width: 100%; + } + @media (min-width: 100px) { + .custom-container { + max-width: 100px; + } + } + @media (min-width: 200px) { + .custom-container { + max-width: 200px; + } + } + @media (min-width: 300px) { + .custom-container { + max-width: 300px; + } + } + `) + }) +}) + +test('media queries can be defined multiple times using objects-in-array syntax', () => { + let config = { + content: [ + { + raw: html`
+ `, + }, + ], + plugins: [ + function ({ addComponents }) { + addComponents([ + { + '.custom-container': { + width: '100%', + }, + '@media (min-width: 100px)': { + '.custom-container': { + maxWidth: '100px', + }, + }, + }, + { + '.btn': { + padding: '1rem .5rem', + display: 'block', + }, + '@media (min-width: 100px)': { + '.btn': { + display: 'inline-block', + }, + }, + }, + ]) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-container { + width: 100%; + } + @media (min-width: 100px) { + .custom-container { + max-width: 100px; + } + } + .btn { + padding: 1rem 0.5rem; + display: block; + } + @media (min-width: 100px) { + .btn { + display: inline-block; + } + } + `) + }) +}) + +test('plugins can create nested rules', () => { + let config = { + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + color: 'white', + padding: '.5rem 1rem', + borderRadius: '.25rem', + '&:hover': { + backgroundColor: 'darkblue', + }, + '@media (min-width: 500px)': { + '&:hover': { + backgroundColor: 'orange', + }, + }, + '> a': { + color: 'red', + }, + 'h1 &': { + color: 'purple', + }, + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + color: #fff; + background-color: #00f; + border-radius: 0.25rem; + padding: 0.5rem 1rem; + } + .btn-blue:hover { + background-color: #00008b; + } + @media (min-width: 500px) { + .btn-blue:hover { + background-color: orange; + } + } + .btn-blue > a { + color: red; + } + h1 .btn-blue { + color: purple; + } + `) + }) +}) + +test('plugins can create rules with escaped selectors', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ e, addUtilities }) { + addUtilities({ + [`.${e('custom-top-1/4')}`]: { + top: '25%', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-top-1\/4 { + top: 25%; + } + `) + }) +}) + +test('plugins can access the current config', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ addComponents, config }) { + let containerClasses = [ + { + '.custom-container': { + width: '100%', + }, + }, + ] + + for (let maxWidth of Object.values(config('theme.customScreens'))) { + containerClasses.push({ + [`@media (min-width: ${maxWidth})`]: { + '.custom-container': { maxWidth }, + }, + }) + } + + addComponents(containerClasses) + }, + ], + theme: { + customScreens: { + sm: '576px', + md: '768px', + lg: '992px', + xl: '1200px', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-container { + width: 100%; + } + @media (min-width: 576px) { + .custom-container { + max-width: 576px; + } + } + @media (min-width: 768px) { + .custom-container { + max-width: 768px; + } + } + @media (min-width: 992px) { + .custom-container { + max-width: 992px; + } + } + @media (min-width: 1200px) { + .custom-container { + max-width: 1200px; + } + } + `) + }) +}) + +test('plugins can check if corePlugins are enabled', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities, corePlugins }) { + addUtilities({ + '.test': { + 'text-color': corePlugins('textColor') ? 'true' : 'false', + opacity: corePlugins('opacity') ? 'true' : 'false', + }, + }) + }, + ], + corePlugins: { textColor: false }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test { + text-color: false; + opacity: true; + } + `) + }) +}) + +test('plugins can check if corePlugins are enabled when using array white-listing', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities, corePlugins }) { + addUtilities({ + '.test': { + 'text-color': corePlugins('textColor') ? 'true' : 'false', + opacity: corePlugins('opacity') ? 'true' : 'false', + }, + }) + }, + ], + corePlugins: ['textColor'], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test { + text-color: true; + opacity: false; + } + `) + }) +}) + +test('plugins can provide fallbacks to keys missing from the config', () => { + let config = { + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents, config }) { + addComponents({ + '.btn': { + borderRadius: config('borderRadius.default', '.25rem'), + }, + }) + }, + ], + theme: { + borderRadius: { + 1: '1px', + 2: '2px', + 4: '4px', + 8: '8px', + }, + }, + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn { + border-radius: 0.25rem; + } + `) + }) +}) + +test('plugins can add multiple sets of utilities and components', () => { + let config = { + content: [ + { + raw: html` +
`, + }, + ], + plugins: [ + function ({ addUtilities, addComponents }) { + addComponents({ + '.card': { + padding: '1rem', + borderRadius: '.25rem', + }, + }) + + addUtilities({ + '.custom-skew-12deg': { + transform: 'skewY(-12deg)', + }, + }) + + addComponents({ + '.btn': { + padding: '1rem .5rem', + display: 'inline-block', + }, + }) + + addUtilities({ + '.custom-border-collapse': { + borderCollapse: 'collapse', + }, + }) + }, + ], + } + + return run('@tailwind components; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .card { + border-radius: 0.25rem; + padding: 1rem; + } + .btn { + padding: 1rem 0.5rem; + display: inline-block; + } + .custom-skew-12deg { + transform: skewY(-12deg); + } + .custom-border-collapse { + border-collapse: collapse; + } + `) + }) +}) + +test('plugins respect prefix and important options by default when adding utilities', () => { + let config = { + prefix: 'tw-', + important: true, + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-custom-rotate-90 { + transform: rotate(90deg) !important; + } + `) + }) +}) + +test('when important is a selector it is used to scope utilities instead of adding !important', () => { + let config = { + prefix: 'tw-', + important: '#app', + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + #app .tw-custom-rotate-90 { + transform: rotate(90deg); + } + `) + }) +}) + +test('when important is a selector it scopes all selectors in a rule, even though defining utilities like this is stupid', () => { + let config = { + important: '#app', + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90, .custom-rotate-1\\/4': { + transform: 'rotate(90deg)', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + #app .custom-rotate-90, + #app .custom-rotate-1\/4 { + transform: rotate(90deg); + } + `) + }) +}) + +test('important utilities are not made double important when important option is used', () => { + let config = { + important: true, + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities({ + '.custom-rotate-90': { + transform: 'rotate(90deg) !important', + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-rotate-90 { + transform: rotate(90deg) !important; + } + `) + }) +}) + +test("component declarations respect the 'prefix' option by default", () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue { + background-color: #00f; + } + `) + }) +}) + +test('all selectors in a rule are prefixed', () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: html` +
`, + }, + ], + plugins: [ + function ({ addUtilities, addComponents }) { + addUtilities({ + '.custom-rotate-90, .custom-rotate-1\\/4': { + transform: 'rotate(90deg)', + }, + }) + addComponents({ + '.btn-blue, .btn-red': { + padding: '10px', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue, + .tw-btn-red { + padding: 10px; + } + `) + }) +}) + +test("component declarations can optionally ignore 'prefix' option", () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents( + { + '.btn-blue': { + backgroundColor: 'blue', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + background-color: #00f; + } + `) + }) +}) + +test("component declarations are not affected by the 'important' option", () => { + let config = { + important: true, + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents }) { + addComponents({ + '.btn-blue': { + backgroundColor: 'blue', + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .btn-blue { + background-color: #00f; + } + `) + }) +}) + +test("plugins can apply the user's chosen prefix to components manually", () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + plugins: [ + function ({ addComponents, prefix }) { + addComponents( + { + [prefix('.btn-blue')]: { + backgroundColor: 'blue', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue { + background-color: #00f; + } + `) + }) +}) + +test('prefix can optionally be ignored for utilities', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities( + { + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-rotate-90 { + transform: rotate(90deg); + } + `) + }) +}) + +test('important can optionally be ignored for utilities', () => { + let config = { + important: true, + content: [{ raw: html`
` }], + plugins: [ + function ({ addUtilities }) { + addUtilities( + { + '.custom-rotate-90': { + transform: 'rotate(90deg)', + }, + }, + { respectImportant: false } + ) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-rotate-90 { + transform: rotate(90deg); + } + `) + }) +}) + +test('prefix will prefix all classes in a selector', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + plugins: [ + function ({ addComponents, prefix }) { + addComponents( + { + [prefix('.btn-blue .w-1\\/4 > h1.text-xl + a .bar')]: { + backgroundColor: 'blue', + }, + }, + { respectPrefix: false } + ) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-btn-blue .tw-w-1\/4 > h1.tw-text-xl + a .tw-bar { + background-color: #00f; + } + `) + }) +}) + +test('plugins can be provided as an object with a handler function', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + { + handler({ addUtilities }) { addUtilities({ '.custom-object-fill': { 'object-fit': 'fill', @@ -25,1273 +1139,95 @@ crosscheck(() => { }, }) }, - ], - } + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .custom-object-fill { + object-fit: fill; + } + .custom-object-contain { + object-fit: contain; + } + .custom-object-cover { + object-fit: cover; + } + `) }) +}) - test('plugins can create utilities with arrays of objects', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities }) { - addUtilities([ - { - '.custom-object-fill': { - 'object-fit': 'fill', - }, - '.custom-object-contain': { - 'object-fit': 'contain', - }, - '.custom-object-cover': { - 'object-fit': 'cover', - }, - }, - ]) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can create utilities with raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities, postcss }) { - addUtilities([ - postcss.rule({ selector: '.custom-object-fill' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'fill', - }), - ]), - postcss.rule({ selector: '.custom-object-contain' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'contain', - }), - ]), - postcss.rule({ selector: '.custom-object-cover' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'cover', - }), - ]), - ]) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can create utilities with mixed object styles and PostCSS nodes', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addUtilities, postcss }) { - addUtilities([ - { - '.custom-object-fill': { - objectFit: 'fill', - }, - }, - postcss.rule({ selector: '.custom-object-contain' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'contain', - }), - ]), - postcss.rule({ selector: '.custom-object-cover' }).append([ - postcss.decl({ - prop: 'object-fit', - value: 'cover', - }), - ]), - ]) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can create components with object syntax', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - color: 'white', - padding: '.5rem 1rem', - borderRadius: '.25rem', - }, - '.btn-blue:hover': { - backgroundColor: 'darkblue', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - `) - }) - }) - - test('plugins can add base styles with object syntax', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addBase }) { - addBase({ - img: { - maxWidth: '100%', - }, - button: { - fontFamily: 'inherit', - }, - }) - }, - ], - corePlugins: { preflight: false }, - } - - return run('@tailwind base', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - img { - max-width: 100%; - } - button { - font-family: inherit; - } - ${defaults} - `) - }) - }) - - test('plugins can add base styles with raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addBase, postcss }) { - addBase([ - postcss.rule({ selector: 'img' }).append([ - postcss.decl({ - prop: 'max-width', - value: '100%', - }), - ]), - postcss.rule({ selector: 'button' }).append([ - postcss.decl({ - prop: 'font-family', - value: 'inherit', - }), - ]), - ]) - }, - ], - corePlugins: { preflight: false }, - } - - return run('@tailwind base', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - img { - max-width: 100%; - } - button { - font-family: inherit; - } - ${defaults} - `) - }) - }) - - test('plugins can create components with raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addComponents, postcss }) { - addComponents([ - postcss.rule({ selector: '.btn-blue' }).append([ - postcss.decl({ - prop: 'background-color', - value: 'blue', - }), - postcss.decl({ - prop: 'color', - value: 'white', - }), - postcss.decl({ - prop: 'padding', - value: '.5rem 1rem', - }), - postcss.decl({ - prop: 'border-radius', - value: '.25rem', - }), - ]), - postcss.rule({ selector: '.btn-blue:hover' }).append([ - postcss.decl({ - prop: 'background-color', - value: 'darkblue', - }), - ]), - ]) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - `) - }) - }) - - test('plugins can create components with mixed object styles and raw PostCSS nodes', () => { - let config = { - content: [ - { - raw: html``, - }, - ], - plugins: [ - function ({ addComponents, postcss }) { - addComponents([ - postcss.rule({ selector: '.btn-blue' }).append([ - postcss.decl({ - prop: 'background-color', - value: 'blue', - }), - postcss.decl({ - prop: 'color', - value: 'white', - }), - postcss.decl({ - prop: 'padding', - value: '.5rem 1rem', - }), - postcss.decl({ - prop: 'border-radius', - value: '.25rem', - }), - ]), - { - '.btn-blue:hover': { - backgroundColor: 'darkblue', - }, - }, - ]) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - `) - }) - }) - - test('plugins can create components with media queries with object syntax', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.custom-container': { - width: '100%', - }, - '@media (min-width: 100px)': { - '.custom-container': { - maxWidth: '100px', - }, - }, - '@media (min-width: 200px)': { - '.custom-container': { - maxWidth: '200px', - }, - }, - '@media (min-width: 300px)': { - '.custom-container': { - maxWidth: '300px', - }, - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-container { - width: 100%; - } - @media (min-width: 100px) { - .custom-container { - max-width: 100px; - } - } - @media (min-width: 200px) { - .custom-container { - max-width: 200px; - } - } - @media (min-width: 300px) { - .custom-container { - max-width: 300px; - } - } - `) - }) - }) - - test('media queries can be defined multiple times using objects-in-array syntax', () => { - let config = { - content: [ - { - raw: html`
- `, - }, - ], - plugins: [ - function ({ addComponents }) { - addComponents([ - { - '.custom-container': { - width: '100%', - }, - '@media (min-width: 100px)': { - '.custom-container': { - maxWidth: '100px', - }, - }, - }, - { - '.btn': { - padding: '1rem .5rem', - display: 'block', - }, - '@media (min-width: 100px)': { - '.btn': { - display: 'inline-block', - }, - }, - }, - ]) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-container { - width: 100%; - } - @media (min-width: 100px) { - .custom-container { - max-width: 100px; - } - } - .btn { - padding: 1rem 0.5rem; - display: block; - } - @media (min-width: 100px) { - .btn { - display: inline-block; - } - } - `) - }) - }) - - test('plugins can create nested rules', () => { - let config = { - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - color: 'white', - padding: '.5rem 1rem', - borderRadius: '.25rem', - '&:hover': { - backgroundColor: 'darkblue', - }, - '@media (min-width: 500px)': { - '&:hover': { - backgroundColor: 'orange', - }, - }, - '> a': { - color: 'red', - }, - 'h1 &': { - color: 'purple', - }, - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - color: #fff; - background-color: #00f; - border-radius: 0.25rem; - padding: 0.5rem 1rem; - } - .btn-blue:hover { - background-color: #00008b; - } - @media (min-width: 500px) { - .btn-blue:hover { - background-color: orange; - } - } - .btn-blue > a { - color: red; - } - h1 .btn-blue { - color: purple; - } - `) - }) - }) - - test('plugins can create rules with escaped selectors', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ e, addUtilities }) { - addUtilities({ - [`.${e('custom-top-1/4')}`]: { - top: '25%', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-top-1\/4 { - top: 25%; - } - `) - }) - }) - - test('plugins can access the current config', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ addComponents, config }) { - let containerClasses = [ - { - '.custom-container': { - width: '100%', - }, - }, - ] - - for (let maxWidth of Object.values(config('theme.customScreens'))) { - containerClasses.push({ - [`@media (min-width: ${maxWidth})`]: { - '.custom-container': { maxWidth }, - }, - }) - } - - addComponents(containerClasses) - }, - ], - theme: { - customScreens: { - sm: '576px', - md: '768px', - lg: '992px', - xl: '1200px', +test('plugins can provide a config but no handler', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + { + config: { + prefix: 'tw-', }, }, - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-container { - width: 100%; - } - @media (min-width: 576px) { - .custom-container { - max-width: 576px; - } - } - @media (min-width: 768px) { - .custom-container { - max-width: 768px; - } - } - @media (min-width: 992px) { - .custom-container { - max-width: 992px; - } - } - @media (min-width: 1200px) { - .custom-container { - max-width: 1200px; - } - } - `) - }) - }) - - test('plugins can check if corePlugins are enabled', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities, corePlugins }) { + { + handler({ addUtilities }) { addUtilities({ - '.test': { - 'text-color': corePlugins('textColor') ? 'true' : 'false', - opacity: corePlugins('opacity') ? 'true' : 'false', + '.custom-object-fill': { + 'object-fit': 'fill', + }, + '.custom-object-contain': { + 'object-fit': 'contain', + }, + '.custom-object-cover': { + 'object-fit': 'cover', }, }) }, - ], - corePlugins: { textColor: false }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test { - text-color: false; - opacity: true; - } - `) - }) - }) - - test('plugins can check if corePlugins are enabled when using array white-listing', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities, corePlugins }) { - addUtilities({ - '.test': { - 'text-color': corePlugins('textColor') ? 'true' : 'false', - opacity: corePlugins('opacity') ? 'true' : 'false', - }, - }) - }, - ], - corePlugins: ['textColor'], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test { - text-color: true; - opacity: false; - } - `) - }) - }) - - test('plugins can provide fallbacks to keys missing from the config', () => { - let config = { - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents, config }) { - addComponents({ - '.btn': { - borderRadius: config('borderRadius.default', '.25rem'), - }, - }) - }, - ], - theme: { - borderRadius: { - 1: '1px', - 2: '2px', - 4: '4px', - 8: '8px', - }, }, - } + ], + } - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn { - border-radius: 0.25rem; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-custom-object-fill { + object-fit: fill; + } + .tw-custom-object-contain { + object-fit: contain; + } + .tw-custom-object-cover { + object-fit: cover; + } + `) }) +}) - test('plugins can add multiple sets of utilities and components', () => { - let config = { - content: [ - { - raw: html` -
`, - }, - ], - plugins: [ - function ({ addUtilities, addComponents }) { - addComponents({ - '.card': { - padding: '1rem', - borderRadius: '.25rem', - }, - }) - - addUtilities({ - '.custom-skew-12deg': { - transform: 'skewY(-12deg)', - }, - }) - - addComponents({ - '.btn': { - padding: '1rem .5rem', - display: 'inline-block', - }, - }) - - addUtilities({ - '.custom-border-collapse': { - borderCollapse: 'collapse', - }, - }) - }, - ], - } - - return run('@tailwind components; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .card { - border-radius: 0.25rem; - padding: 1rem; - } - .btn { - padding: 1rem 0.5rem; - display: inline-block; - } - .custom-skew-12deg { - transform: skewY(-12deg); - } - .custom-border-collapse { - border-collapse: collapse; - } - `) - }) - }) - - test('plugins respect prefix and important options by default when adding utilities', () => { - let config = { - prefix: 'tw-', - important: true, - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-custom-rotate-90 { - transform: rotate(90deg) !important; - } - `) - }) - }) - - test('when important is a selector it is used to scope utilities instead of adding !important', () => { - let config = { - prefix: 'tw-', - important: '#app', - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - #app .tw-custom-rotate-90 { - transform: rotate(90deg); - } - `) - }) - }) - - test('when important is a selector it scopes all selectors in a rule, even though defining utilities like this is stupid', () => { - let config = { - important: '#app', - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90, .custom-rotate-1\\/4': { - transform: 'rotate(90deg)', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - #app .custom-rotate-90, - #app .custom-rotate-1\/4 { - transform: rotate(90deg); - } - `) - }) - }) - - test('important utilities are not made double important when important option is used', () => { - let config = { - important: true, - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities({ - '.custom-rotate-90': { - transform: 'rotate(90deg) !important', - }, - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-rotate-90 { - transform: rotate(90deg) !important; - } - `) - }) - }) - - test("component declarations respect the 'prefix' option by default", () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue { - background-color: #00f; - } - `) - }) - }) - - test('all selectors in a rule are prefixed', () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: html` -
`, - }, - ], - plugins: [ - function ({ addUtilities, addComponents }) { - addUtilities({ - '.custom-rotate-90, .custom-rotate-1\\/4': { - transform: 'rotate(90deg)', - }, - }) - addComponents({ - '.btn-blue, .btn-red': { - padding: '10px', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue, - .tw-btn-red { - padding: 10px; - } - `) - }) - }) - - test("component declarations can optionally ignore 'prefix' option", () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents( - { - '.btn-blue': { - backgroundColor: 'blue', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - background-color: #00f; - } - `) - }) - }) - - test("component declarations are not affected by the 'important' option", () => { - let config = { - important: true, - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents }) { - addComponents({ - '.btn-blue': { - backgroundColor: 'blue', - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .btn-blue { - background-color: #00f; - } - `) - }) - }) - - test("plugins can apply the user's chosen prefix to components manually", () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - plugins: [ - function ({ addComponents, prefix }) { - addComponents( - { - [prefix('.btn-blue')]: { - backgroundColor: 'blue', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue { - background-color: #00f; - } - `) - }) - }) - - test('prefix can optionally be ignored for utilities', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities( - { - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-rotate-90 { - transform: rotate(90deg); - } - `) - }) - }) - - test('important can optionally be ignored for utilities', () => { - let config = { - important: true, - content: [{ raw: html`
` }], - plugins: [ - function ({ addUtilities }) { - addUtilities( - { - '.custom-rotate-90': { - transform: 'rotate(90deg)', - }, - }, - { respectImportant: false } - ) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-rotate-90 { - transform: rotate(90deg); - } - `) - }) - }) - - test('prefix will prefix all classes in a selector', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - plugins: [ - function ({ addComponents, prefix }) { - addComponents( - { - [prefix('.btn-blue .w-1\\/4 > h1.text-xl + a .bar')]: { - backgroundColor: 'blue', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-btn-blue .tw-w-1\/4 > h1.tw-text-xl + a .tw-bar { - background-color: #00f; - } - `) - }) - }) - - test('plugins can be provided as an object with a handler function', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - { - handler({ addUtilities }) { - addUtilities({ - '.custom-object-fill': { - 'object-fit': 'fill', - }, - '.custom-object-contain': { - 'object-fit': 'contain', - }, - '.custom-object-cover': { - 'object-fit': 'cover', - }, - }) - }, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .custom-object-fill { - object-fit: fill; - } - .custom-object-contain { - object-fit: contain; - } - .custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can provide a config but no handler', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - { - config: { - prefix: 'tw-', - }, - }, - { - handler({ addUtilities }) { - addUtilities({ - '.custom-object-fill': { - 'object-fit': 'fill', - }, - '.custom-object-contain': { - 'object-fit': 'contain', - }, - '.custom-object-cover': { - 'object-fit': 'cover', - }, - }) - }, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tw-custom-object-fill { - object-fit: fill; - } - .tw-custom-object-contain { - object-fit: contain; - } - .tw-custom-object-cover { - object-fit: cover; - } - `) - }) - }) - - test('plugins can be created using the `createPlugin` function', () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, +test('plugins can be created using the `createPlugin` function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + screens: { + sm: '400px', }, - plugins: [ - createPlugin( - function ({ addUtilities, theme }) { - addUtilities( - Object.fromEntries( - Object.entries(theme('testPlugin')).map(([k, v]) => [ - `.test-${k}`, - { testProperty: v }, - ]) - ) - ) - }, - { - theme: { - testPlugin: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - }, - } - ), - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test-sm { - test-property: 1rem; - } - .test-md { - test-property: 2rem; - } - .test-lg { - test-property: 3rem; - } - .hover\:test-sm:hover { - test-property: 1rem; - } - @media (min-width: 400px) { - .sm\:test-sm { - test-property: 1rem; - } - } - `) - }) - }) - - test('plugins with extra options can be created using the `createPlugin.withOptions` function', () => { - let plugin = createPlugin.withOptions( - function ({ className }) { - return function ({ addUtilities, theme }) { + }, + plugins: [ + createPlugin( + function ({ addUtilities, theme }) { addUtilities( Object.fromEntries( Object.entries(theme('testPlugin')).map(([k, v]) => [ - `.${className}-${k}`, + `.test-${k}`, { testProperty: v }, ]) ) ) - } - }, - function () { - return { + }, + { theme: { testPlugin: { sm: '1rem', @@ -1300,169 +1236,36 @@ crosscheck(() => { }, }, } + ), + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-sm { + test-property: 1rem; } - ) - - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - }, - plugins: [plugin({ className: 'banana' })], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .banana-sm { - test-property: 1rem; - } - .banana-md { - test-property: 2rem; - } - .banana-lg { - test-property: 3rem; - } - .hover\:banana-sm:hover { - test-property: 1rem; - } - @media (min-width: 400px) { - .sm\:banana-sm { - test-property: 1rem; - } - } - `) - }) - }) - - test('plugins should cache correctly', () => { - let plugin = createPlugin.withOptions( - ({ className = 'banana' } = {}) => - ({ addComponents }) => { - addComponents({ [`.${className}`]: { position: 'absolute' } }) - } - ) - - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - }, - } - - function internalRun(options = {}) { - return run('@tailwind components', { - ...config, - plugins: [plugin(options)], - }) - } - - return Promise.all([internalRun(), internalRun({ className: 'apple' })]).then( - ([result1, result2]) => { - let expected1 = css` - .banana { - position: absolute; - } - @media (min-width: 400px) { - .sm\:banana { - position: absolute; - } - } - ` - - let expected2 = css` - .apple { - position: absolute; - } - @media (min-width: 400px) { - .sm\:apple { - position: absolute; - } - } - ` - - expect(result1.css).toMatchCss(expected1) - expect(result2.css).toMatchCss(expected2) + .test-md { + test-property: 2rem; } - ) - }) - - test('plugins created using `createPlugin.withOptions` do not need to be invoked if the user wants to use the default options', () => { - let plugin = createPlugin.withOptions( - function ({ className } = { className: 'banana' }) { - return function ({ addUtilities, theme }) { - addUtilities( - Object.fromEntries( - Object.entries(theme('testPlugin')).map(([k, v]) => [ - `.${className}-${k}`, - { testProperty: v }, - ]) - ) - ) - } - }, - function () { - return { - theme: { - testPlugin: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - }, + .test-lg { + test-property: 3rem; + } + .hover\:test-sm:hover { + test-property: 1rem; + } + @media (min-width: 400px) { + .sm\:test-sm { + test-property: 1rem; } } - ) - - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - }, - plugins: [plugin], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .banana-sm { - test-property: 1rem; - } - .banana-md { - test-property: 2rem; - } - .banana-lg { - test-property: 3rem; - } - .hover\:banana-sm:hover { - test-property: 1rem; - } - @media (min-width: 400px) { - .sm\:banana-sm { - test-property: 1rem; - } - } - `) - }) + `) }) +}) - test('the configFunction parameter is optional when using the `createPlugin.withOptions` function', () => { - let plugin = createPlugin.withOptions(function ({ className }) { +test('plugins with extra options can be created using the `createPlugin.withOptions` function', () => { + let plugin = createPlugin.withOptions( + function ({ className }) { return function ({ addUtilities, theme }) { addUtilities( Object.fromEntries( @@ -1473,461 +1276,641 @@ crosscheck(() => { ) ) } - }) - - let config = { - content: [ - { - raw: html`
`, + }, + function () { + return { + theme: { + testPlugin: { + sm: '1rem', + md: '2rem', + lg: '3rem', + }, }, - ], - corePlugins: [], - theme: { - screens: { - sm: '400px', - }, - testPlugin: { - sm: '1px', - md: '2px', - lg: '3px', - }, - }, - plugins: [plugin({ className: 'banana' })], + } } + ) - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .banana-sm { - test-property: 1px; + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + }, + plugins: [plugin({ className: 'banana' })], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .banana-sm { + test-property: 1rem; + } + .banana-md { + test-property: 2rem; + } + .banana-lg { + test-property: 3rem; + } + .hover\:banana-sm:hover { + test-property: 1rem; + } + @media (min-width: 400px) { + .sm\:banana-sm { + test-property: 1rem; } - .banana-md { - test-property: 2px; - } - .banana-lg { - test-property: 3px; - } - .hover\:banana-sm:hover { - test-property: 1px; - } - @media (min-width: 400px) { - .sm\:banana-sm { - test-property: 1px; - } - } - `) - }) + } + `) + }) +}) + +test('plugins should cache correctly', () => { + let plugin = createPlugin.withOptions(({ className = 'banana' } = {}) => ({ addComponents }) => { + addComponents({ [`.${className}`]: { position: 'absolute' } }) }) - test('keyframes are not escaped', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - plugins: [ - function ({ matchUtilities }) { - matchUtilities({ - foo: (value) => { - return { - [`@keyframes ${value}`]: { - '25.001%': { - color: 'black', - }, - }, - animation: `${value} 1s infinite`, - } - }, - }) - }, - ], - } + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @keyframes abc { + function internalRun(options = {}) { + return run('@tailwind components', { + ...config, + plugins: [plugin(options)], + }) + } + + return Promise.all([internalRun(), internalRun({ className: 'apple' })]).then( + ([result1, result2]) => { + let expected1 = css` + .banana { + position: absolute; + } + @media (min-width: 400px) { + .sm\:banana { + position: absolute; + } + } + ` + + let expected2 = css` + .apple { + position: absolute; + } + @media (min-width: 400px) { + .sm\:apple { + position: absolute; + } + } + ` + + expect(result1.css).toMatchCss(expected1) + expect(result2.css).toMatchCss(expected2) + } + ) +}) + +test('plugins created using `createPlugin.withOptions` do not need to be invoked if the user wants to use the default options', () => { + let plugin = createPlugin.withOptions( + function ({ className } = { className: 'banana' }) { + return function ({ addUtilities, theme }) { + addUtilities( + Object.fromEntries( + Object.entries(theme('testPlugin')).map(([k, v]) => [ + `.${className}-${k}`, + { testProperty: v }, + ]) + ) + ) + } + }, + function () { + return { + theme: { + testPlugin: { + sm: '1rem', + md: '2rem', + lg: '3rem', + }, + }, + } + } + ) + + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + }, + plugins: [plugin], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .banana-sm { + test-property: 1rem; + } + .banana-md { + test-property: 2rem; + } + .banana-lg { + test-property: 3rem; + } + .hover\:banana-sm:hover { + test-property: 1rem; + } + @media (min-width: 400px) { + .sm\:banana-sm { + test-property: 1rem; + } + } + `) + }) +}) + +test('the configFunction parameter is optional when using the `createPlugin.withOptions` function', () => { + let plugin = createPlugin.withOptions(function ({ className }) { + return function ({ addUtilities, theme }) { + addUtilities( + Object.fromEntries( + Object.entries(theme('testPlugin')).map(([k, v]) => [ + `.${className}-${k}`, + { testProperty: v }, + ]) + ) + ) + } + }) + + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: [], + theme: { + screens: { + sm: '400px', + }, + testPlugin: { + sm: '1px', + md: '2px', + lg: '3px', + }, + }, + plugins: [plugin({ className: 'banana' })], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .banana-sm { + test-property: 1px; + } + .banana-md { + test-property: 2px; + } + .banana-lg { + test-property: 3px; + } + .hover\:banana-sm:hover { + test-property: 1px; + } + @media (min-width: 400px) { + .sm\:banana-sm { + test-property: 1px; + } + } + `) + }) +}) + +test('keyframes are not escaped', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [ + function ({ matchUtilities }) { + matchUtilities({ + foo: (value) => { + return { + [`@keyframes ${value}`]: { + '25.001%': { + color: 'black', + }, + }, + animation: `${value} 1s infinite`, + } + }, + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @keyframes abc { + 25.001% { + color: #000; + } + } + .foo-\[abc\] { + animation: 1s infinite abc; + } + @media (min-width: 768px) { + @keyframes def { 25.001% { color: #000; } } - .foo-\[abc\] { - animation: 1s infinite abc; + .md\:foo-\[def\] { + animation: 1s infinite def; } - @media (min-width: 768px) { - @keyframes def { - 25.001% { - color: #000; - } - } - .md\:foo-\[def\] { - animation: 1s infinite def; - } - } - `) - }) - }) - - test('font sizes are retrieved without default line-heights or letter-spacing using theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - fontSize: { - sm: ['14px', '20px'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - fontSize: theme('fontSize.sm'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - font-size: 14px; - } - `) - }) - }) - - test('outlines are retrieved without outline-offset using theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - outline: { - black: ['2px dotted black', '4px'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - outline: theme('outline.black'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - outline: 2px dotted #000; - } - `) - }) - }) - - test('box-shadow values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - boxShadow: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - boxShadow: theme('boxShadow.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - box-shadow: width, height; - } - `) - }) - }) - - test('transition-property values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionProperty: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionProperty: theme('transitionProperty.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-property: width, height; - } - `) - }) - }) - - test('transition-duration values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionDuration: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionDuration: theme('transitionDuration.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-duration: width, height; - } - `) - }) - }) - - test('transition-delay values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionDuration: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionDuration: theme('transitionDuration.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-duration: width, height; - } - `) - }) - }) - - test('transition-timing-function values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - transitionTimingFunction: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - transitionTimingFunction: theme('transitionTimingFunction.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - transition-timing-function: width, height; - } - `) - }) - }) - - test('background-image values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - backgroundImage: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - backgroundImage: theme('backgroundImage.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - background-image: width, height; - } - `) - }) - }) - - test('background-size values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - backgroundSize: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - backgroundSize: theme('backgroundSize.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - background-size: width, height; - } - `) - }) - }) - - test('background-color values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - backgroundColor: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - backgroundColor: theme('backgroundColor.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - background-color: width, height; - } - `) - }) - }) - - test('cursor values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - cursor: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - cursor: theme('cursor.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - cursor: width, height; - } - `) - }) - }) - - test('animation values are joined when retrieved using the theme function', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: [], - theme: { - animation: { - lol: ['width', 'height'], - }, - }, - plugins: [ - function ({ addComponents, theme }) { - addComponents({ - '.foo': { - animation: theme('animation.lol'), - }, - }) - }, - ], - } - - return run('@tailwind components', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo { - animation: width, height; - } - `) - }) - }) - - test('custom properties are not converted to kebab-case when added to base layer', () => { - let config = { - content: [], - plugins: [ - function ({ addBase }) { - addBase({ - ':root': { - '--colors-primaryThing-500': '0, 0, 255', - }, - }) - }, - ], - } - - return run('@tailwind base', config).then((result) => { - expect(result.css).toContain(`--colors-primaryThing-500: 0, 0, 255;`) - }) + } + `) + }) +}) + +test('font sizes are retrieved without default line-heights or letter-spacing using theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + fontSize: { + sm: ['14px', '20px'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + fontSize: theme('fontSize.sm'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + font-size: 14px; + } + `) + }) +}) + +test('outlines are retrieved without outline-offset using theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + outline: { + black: ['2px dotted black', '4px'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + outline: theme('outline.black'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + outline: 2px dotted #000; + } + `) + }) +}) + +test('box-shadow values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + boxShadow: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + boxShadow: theme('boxShadow.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + box-shadow: width, height; + } + `) + }) +}) + +test('transition-property values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionProperty: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionProperty: theme('transitionProperty.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-property: width, height; + } + `) + }) +}) + +test('transition-duration values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionDuration: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionDuration: theme('transitionDuration.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-duration: width, height; + } + `) + }) +}) + +test('transition-delay values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionDuration: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionDuration: theme('transitionDuration.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-duration: width, height; + } + `) + }) +}) + +test('transition-timing-function values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + transitionTimingFunction: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + transitionTimingFunction: theme('transitionTimingFunction.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + transition-timing-function: width, height; + } + `) + }) +}) + +test('background-image values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + backgroundImage: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + backgroundImage: theme('backgroundImage.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + background-image: width, height; + } + `) + }) +}) + +test('background-size values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + backgroundSize: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + backgroundSize: theme('backgroundSize.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + background-size: width, height; + } + `) + }) +}) + +test('background-color values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + backgroundColor: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + backgroundColor: theme('backgroundColor.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + background-color: width, height; + } + `) + }) +}) + +test('cursor values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + cursor: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + cursor: theme('cursor.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + cursor: width, height; + } + `) + }) +}) + +test('animation values are joined when retrieved using the theme function', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: [], + theme: { + animation: { + lol: ['width', 'height'], + }, + }, + plugins: [ + function ({ addComponents, theme }) { + addComponents({ + '.foo': { + animation: theme('animation.lol'), + }, + }) + }, + ], + } + + return run('@tailwind components', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo { + animation: width, height; + } + `) + }) +}) + +test('custom properties are not converted to kebab-case when added to base layer', () => { + let config = { + content: [], + plugins: [ + function ({ addBase }) { + addBase({ + ':root': { + '--colors-primaryThing-500': '0, 0, 255', + }, + }) + }, + ], + } + + return run('@tailwind base', config).then((result) => { + expect(result.css).toContain(`--colors-primaryThing-500: 0, 0, 255;`) }) }) diff --git a/tests/custom-separator.test.js b/tests/custom-separator.test.js index adc1d55af..3b1708dfb 100644 --- a/tests/custom-separator.test.js +++ b/tests/custom-separator.test.js @@ -1,57 +1,55 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('custom separator', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
- `, - }, - ], - separator: '_', - } +test('custom separator', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+ `, + }, + ], + separator: '_', + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .group:hover .group-hover_focus-within_text-left:focus-within { - text-align: left; - } - :is([dir='rtl'] .rtl_active_text-center:active) { + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group:hover .group-hover_focus-within_text-left:focus-within { + text-align: left; + } + :is([dir='rtl'] .rtl_active_text-center:active) { + text-align: center; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe_hover_text-center:hover { text-align: center; } - @media (prefers-reduced-motion: no-preference) { - .motion-safe_hover_text-center:hover { - text-align: center; - } + } + :is(.dark .dark_focus_text-left:focus) { + text-align: left; + } + @media (min-width: 768px) { + .md_hover_text-right:hover { + text-align: right; } - :is(.dark .dark_focus_text-left:focus) { - text-align: left; - } - @media (min-width: 768px) { - .md_hover_text-right:hover { - text-align: right; - } - } - `) - }) - }) - - test('dash is not supported', () => { - let config = { - darkMode: 'class', - content: [{ raw: 'lg-hover-font-bold' }], - separator: '-', - } - - return expect(run('@tailwind utilities', config)).rejects.toThrowError( - "The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead." - ) + } + `) }) }) + +test('dash is not supported', () => { + let config = { + darkMode: 'class', + content: [{ raw: 'lg-hover-font-bold' }], + separator: '-', + } + + return expect(run('@tailwind utilities', config)).rejects.toThrowError( + "The '-' character cannot be used as a custom separator in JIT mode due to parsing ambiguity. Please use another character like '_' instead." + ) +}) diff --git a/tests/custom-transformers.test.js b/tests/custom-transformers.test.js index 14e3abac0..2715a7155 100644 --- a/tests/custom-transformers.test.js +++ b/tests/custom-transformers.test.js @@ -1,72 +1,67 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' function customTransformer(content) { return content.replace(/uppercase/g, 'lowercase') } -crosscheck(({ stable, oxide }) => { - oxide.test.todo('transform function') - stable.test('transform function', () => { - let config = { - content: { - files: [{ raw: html`
` }], - transform: customTransformer, - }, - } +test('transform function', () => { + let config = { + content: { + files: [{ raw: html`
` }], + transform: customTransformer, + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .lowercase { - text-transform: lowercase; - } - `) - }) - }) - - oxide.test.todo('transform.DEFAULT') - stable.test('transform.DEFAULT', () => { - let config = { - content: { - files: [{ raw: html`
` }], - transform: { - DEFAULT: customTransformer, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .lowercase { - text-transform: lowercase; - } - `) - }) - }) - - oxide.test.todo('transform.{extension}') - stable.test('transform.{extension}', () => { - let config = { - content: { - files: [ - { raw: 'blah blah blah', extension: 'html' }, - { raw: 'blah blah blah', extension: 'php' }, - ], - transform: { - html: () => 'uppercase', - php: () => 'lowercase', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - .lowercase { - text-transform: lowercase; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .lowercase { + text-transform: lowercase; + } + `) + }) +}) + +test('transform.DEFAULT', () => { + let config = { + content: { + files: [{ raw: html`
` }], + transform: { + DEFAULT: customTransformer, + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .lowercase { + text-transform: lowercase; + } + `) + }) +}) + +test('transform.{extension}', () => { + let config = { + content: { + files: [ + { raw: 'blah blah blah', extension: 'html' }, + { raw: 'blah blah blah', extension: 'php' }, + ], + transform: { + html: () => 'uppercase', + php: () => 'lowercase', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + .lowercase { + text-transform: lowercase; + } + `) }) }) diff --git a/tests/customConfig.test.js b/tests/customConfig.test.js index 5b83f9f2e..b8f459144 100644 --- a/tests/customConfig.test.js +++ b/tests/customConfig.test.js @@ -2,37 +2,100 @@ import fs from 'fs' import path from 'path' import inTempDirectory from '../jest/runInTempDirectory' -import { crosscheck, run, html, css, javascript } from './util/run' +import { run, html, css, javascript } from './util/run' const defaultConfigFile = 'tailwind.config.js' const cjsConfigFile = 'tailwind.config.cjs' -crosscheck(() => { - test('it uses the values from the custom config file', () => { - let config = require(path.resolve(`${__dirname}/fixtures/custom-config.js`)) +test('it uses the values from the custom config file', () => { + let config = require(path.resolve(`${__dirname}/fixtures/custom-config.js`)) - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; } - `) - }) + } + `) }) +}) - test('custom config can be passed as an object', () => { - let config = { +test('custom config can be passed as an object', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + screens: { + mobile: '400px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +test('custom config path can be passed using `config` property in an object', () => { + let config = { + config: path.resolve(`${__dirname}/fixtures/custom-config.js`), + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +test('custom config can be passed under the `config` property', () => { + let config = { + config: { content: [{ raw: html`
` }], theme: { screens: { mobile: '400px', }, }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +test('tailwind.config.cjs is picked up by default', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(cjsConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities').then((result) => { expect(result.css).toMatchFormattedCss(css` @media (min-width: 400px) { .mobile\:font-bold { @@ -42,349 +105,284 @@ crosscheck(() => { `) }) }) - - test('custom config path can be passed using `config` property in an object', () => { - let config = { - config: path.resolve(`${__dirname}/fixtures/custom-config.js`), - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - test('custom config can be passed under the `config` property', () => { - let config = { - config: { - content: [{ raw: html`
` }], - theme: { - screens: { - mobile: '400px', - }, - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - test('tailwind.config.cjs is picked up by default', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(cjsConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities').then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('tailwind.config.js is picked up by default', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(defaultConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities').then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('tailwind.config.cjs is picked up by default when passing an empty object', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(cjsConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities', {}).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('tailwind.config.js is picked up by default when passing an empty object', () => { - return inTempDirectory(() => { - fs.writeFileSync( - path.resolve(defaultConfigFile), - javascript`module.exports = { - content: [{ raw: '
' }], - theme: { - screens: { - mobile: '400px', - }, - }, - }` - ) - - return run('@tailwind utilities', {}).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { - .mobile\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - }) - - test('the default config can be overridden using the presets key', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - { - theme: { - extend: { minHeight: { secondary: '24px' } }, - }, - }, - ], - theme: { - extend: { minHeight: { primary: '48px' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .min-h-0 { - min-height: 0; - } - .min-h-primary { - min-height: 48px; - } - .min-h-secondary { - min-height: 24px; - } - `) - }) - }) - - test('presets can be functions', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - () => ({ - theme: { - extend: { minHeight: { secondary: '24px' } }, - }, - }), - ], - theme: { - extend: { minHeight: { primary: '48px' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .min-h-0 { - min-height: 0; - } - .min-h-primary { - min-height: 48px; - } - .min-h-secondary { - min-height: 24px; - } - `) - }) - }) - - test('the default config can be removed by using an empty presets key in a preset', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - { - presets: [], - theme: { - extend: { minHeight: { secondary: '24px' } }, - }, - }, - ], - theme: { - extend: { minHeight: { primary: '48px' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .min-h-primary { - min-height: 48px; - } - .min-h-secondary { - min-height: 24px; - } - `) - }) - }) - - test('presets can have their own presets', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - { - presets: [], - theme: { - colors: { red: '#dd0000' }, - }, - }, - { - presets: [ - { - presets: [], - theme: { - colors: { - transparent: 'transparent', - red: '#ff0000', - }, - }, - }, - ], - theme: { - extend: { - colors: { - black: 'black', - red: '#ee0000', - }, - backgroundColor: (theme) => theme('colors'), - }, - }, - corePlugins: ['backgroundColor'], - }, - ], - theme: { - extend: { colors: { white: 'white' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-black { - background-color: #000; - } - .bg-red { - background-color: #e00; - } - .bg-transparent { - background-color: #0000; - } - .bg-white { - background-color: #fff; - } - `) - }) - }) - - test('function presets can be mixed with object presets', () => { - let config = { - content: [{ raw: html`
` }], - presets: [ - () => ({ - presets: [], - theme: { - colors: { red: '#dd0000' }, - }, - }), - { - presets: [ - () => ({ - presets: [], - theme: { - colors: { - transparent: 'transparent', - red: '#ff0000', - }, - }, - }), - ], - theme: { - extend: { - colors: { - black: 'black', - red: '#ee0000', - }, - backgroundColor: (theme) => theme('colors'), - }, - }, - corePlugins: ['backgroundColor'], - }, - ], - theme: { - extend: { colors: { white: 'white' } }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-black { - background-color: #000; - } - .bg-red { - background-color: #e00; - } - .bg-transparent { - background-color: #0000; - } - .bg-white { - background-color: #fff; - } - `) - }) - }) +}) + +test('tailwind.config.js is picked up by default', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(defaultConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities').then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) + }) +}) + +test('tailwind.config.cjs is picked up by default when passing an empty object', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(cjsConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities', {}).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) + }) +}) + +test('tailwind.config.js is picked up by default when passing an empty object', () => { + return inTempDirectory(() => { + fs.writeFileSync( + path.resolve(defaultConfigFile), + javascript`module.exports = { + content: [{ raw: '
' }], + theme: { + screens: { + mobile: '400px', + }, + }, + }` + ) + + return run('@tailwind utilities', {}).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 400px) { + .mobile\:font-bold { + font-weight: 700; + } + } + `) + }) + }) +}) + +test('the default config can be overridden using the presets key', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + { + theme: { + extend: { minHeight: { secondary: '24px' } }, + }, + }, + ], + theme: { + extend: { minHeight: { primary: '48px' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .min-h-0 { + min-height: 0; + } + .min-h-primary { + min-height: 48px; + } + .min-h-secondary { + min-height: 24px; + } + `) + }) +}) + +test('presets can be functions', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + () => ({ + theme: { + extend: { minHeight: { secondary: '24px' } }, + }, + }), + ], + theme: { + extend: { minHeight: { primary: '48px' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .min-h-0 { + min-height: 0; + } + .min-h-primary { + min-height: 48px; + } + .min-h-secondary { + min-height: 24px; + } + `) + }) +}) + +test('the default config can be removed by using an empty presets key in a preset', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + { + presets: [], + theme: { + extend: { minHeight: { secondary: '24px' } }, + }, + }, + ], + theme: { + extend: { minHeight: { primary: '48px' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .min-h-primary { + min-height: 48px; + } + .min-h-secondary { + min-height: 24px; + } + `) + }) +}) + +test('presets can have their own presets', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + { + presets: [], + theme: { + colors: { red: '#dd0000' }, + }, + }, + { + presets: [ + { + presets: [], + theme: { + colors: { + transparent: 'transparent', + red: '#ff0000', + }, + }, + }, + ], + theme: { + extend: { + colors: { + black: 'black', + red: '#ee0000', + }, + backgroundColor: (theme) => theme('colors'), + }, + }, + corePlugins: ['backgroundColor'], + }, + ], + theme: { + extend: { colors: { white: 'white' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-black { + background-color: #000; + } + .bg-red { + background-color: #e00; + } + .bg-transparent { + background-color: #0000; + } + .bg-white { + background-color: #fff; + } + `) + }) +}) + +test('function presets can be mixed with object presets', () => { + let config = { + content: [{ raw: html`
` }], + presets: [ + () => ({ + presets: [], + theme: { + colors: { red: '#dd0000' }, + }, + }), + { + presets: [ + () => ({ + presets: [], + theme: { + colors: { + transparent: 'transparent', + red: '#ff0000', + }, + }, + }), + ], + theme: { + extend: { + colors: { + black: 'black', + red: '#ee0000', + }, + backgroundColor: (theme) => theme('colors'), + }, + }, + corePlugins: ['backgroundColor'], + }, + ], + theme: { + extend: { colors: { white: 'white' } }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-black { + background-color: #000; + } + .bg-red { + background-color: #e00; + } + .bg-transparent { + background-color: #0000; + } + .bg-white { + background-color: #fff; + } + `) + }) }) diff --git a/tests/dark-mode.test.js b/tests/dark-mode.test.js index ce06496b2..0c5273991 100644 --- a/tests/dark-mode.test.js +++ b/tests/dark-mode.test.js @@ -1,123 +1,121 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - it('should be possible to use the darkMode "class" mode', () => { - let config = { - darkMode: 'class', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should be possible to use the darkMode "class" mode', () => { + let config = { + darkMode: 'class', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - :is(.dark .dark\:font-bold) { - font-weight: 700; - } - `) - }) - }) - - it('should be possible to change the class name', () => { - let config = { - darkMode: ['class', '.test-dark'], - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - :is(.test-dark .dark\:font-bold) { - font-weight: 700; - } - `) - }) - }) - - it('should be possible to use the darkMode "media" mode', () => { - let config = { - darkMode: 'media', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - .dark\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('should default to the `media` mode when no mode is provided', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - .dark\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('should default to the `media` mode when mode is set to `false`', () => { - let config = { - darkMode: false, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-color-scheme: dark) { - .dark\:font-bold { - font-weight: 700; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + :is(.dark .dark\:font-bold) { + font-weight: 700; + } + `) + }) +}) + +it('should be possible to change the class name', () => { + let config = { + darkMode: ['class', '.test-dark'], + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + :is(.test-dark .dark\:font-bold) { + font-weight: 700; + } + `) + }) +}) + +it('should be possible to use the darkMode "media" mode', () => { + let config = { + darkMode: 'media', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + .dark\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +it('should default to the `media` mode when no mode is provided', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + .dark\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +it('should default to the `media` mode when mode is set to `false`', () => { + let config = { + darkMode: false, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-color-scheme: dark) { + .dark\:font-bold { + font-weight: 700; + } + } + `) }) }) diff --git a/tests/detect-nesting.test.js b/tests/detect-nesting.test.js index 39af6d422..08eeacf98 100644 --- a/tests/detect-nesting.test.js +++ b/tests/detect-nesting.test.js @@ -1,130 +1,128 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - it('should warn when we detect nested css', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should warn when we detect nested css', () => { + let config = { + content: [{ raw: html`
` }], + } - let input = css` - @tailwind utilities; + let input = css` + @tailwind utilities; - .nested { - .example { - } + .nested { + .example { } - ` - - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(1) - expect(result.messages).toMatchObject([ - { - type: 'warning', - text: [ - 'Nested CSS was detected, but CSS nesting has not been configured correctly.', - 'Please enable a CSS nesting plugin *before* Tailwind in your configuration.', - 'See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting', - ].join('\n'), - }, - ]) - }) - }) - - it('should not warn when we detect nested css inside css @layer rules', () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(1) + expect(result.messages).toMatchObject([ + { + type: 'warning', + text: [ + 'Nested CSS was detected, but CSS nesting has not been configured correctly.', + 'Please enable a CSS nesting plugin *before* Tailwind in your configuration.', + 'See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting', + ].join('\n'), + }, + ]) + }) +}) + +it('should not warn when we detect nested css inside css @layer rules', () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @layer tw-base, tw-components, tw-utilities; + @layer tw-utilities { + @tailwind utilities; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` @layer tw-base, tw-components, tw-utilities; @layer tw-utilities { - @tailwind utilities; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @layer tw-base, tw-components, tw-utilities; - @layer tw-utilities { - .underline { - text-decoration-line: underline; - } - } - `) - expect(result.messages).toHaveLength(0) - }) - }) - - it('should warn when we detect namespaced @tailwind at rules', () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - .namespace { - @tailwind utilities; - } - ` - - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(1) - expect(result.messages).toMatchObject([ - { - type: 'warning', - text: [ - 'Nested @tailwind rules were detected, but are not supported.', - "Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix", - 'Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy', - ].join('\n'), - }, - ]) - }) - }) - - it('should not warn when nesting a single rule inside a media query', () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind utilities; - - @media (min-width: 768px) { - .nested { + .underline { + text-decoration-line: underline; } } - ` - - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(0) - expect(result.messages).toEqual([]) - }) + `) + expect(result.messages).toHaveLength(0) }) +}) - it('should only warn for the first detected nesting ', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should warn when we detect namespaced @tailwind at rules', () => { + let config = { + content: [{ raw: html`
` }], + } - let input = css` + let input = css` + .namespace { @tailwind utilities; + } + ` + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(1) + expect(result.messages).toMatchObject([ + { + type: 'warning', + text: [ + 'Nested @tailwind rules were detected, but are not supported.', + "Consider using a prefix to scope Tailwind's classes: https://tailwindcss.com/docs/configuration#prefix", + 'Alternatively, use the important selector strategy: https://tailwindcss.com/docs/configuration#selector-strategy', + ].join('\n'), + }, + ]) + }) +}) + +it('should not warn when nesting a single rule inside a media query', () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + + @media (min-width: 768px) { .nested { - .example { - } + } + } + ` - .other { - } + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(0) + expect(result.messages).toEqual([]) + }) +}) + +it('should only warn for the first detected nesting ', () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + + .nested { + .example { } .other { - .example { - } } - ` + } - return run(input, config).then((result) => { - expect(result.messages).toHaveLength(1) - }) + .other { + .example { + } + } + ` + + return run(input, config).then((result) => { + expect(result.messages).toHaveLength(1) }) }) diff --git a/tests/escapeClassName.test.js b/tests/escapeClassName.test.js index cdd834a79..7a8cd7b7b 100644 --- a/tests/escapeClassName.test.js +++ b/tests/escapeClassName.test.js @@ -1,8 +1,5 @@ import escapeClassName from '../src/util/escapeClassName' -import { crosscheck } from './util/run' -crosscheck(() => { - test('invalid characters are escaped', () => { - expect(escapeClassName('w:_$-1/2')).toEqual('w\\:_\\$-1\\/2') - }) +test('invalid characters are escaped', () => { + expect(escapeClassName('w:_$-1/2')).toEqual('w\\:_\\$-1\\/2') }) diff --git a/tests/evaluateTailwindFunctions.test.js b/tests/evaluateTailwindFunctions.test.js index 34eb5adc0..52f1fed07 100644 --- a/tests/evaluateTailwindFunctions.test.js +++ b/tests/evaluateTailwindFunctions.test.js @@ -2,7 +2,7 @@ import fs from 'fs' import path from 'path' import postcss from 'postcss' import plugin from '../src/lib/evaluateTailwindFunctions' -import { crosscheck, run as runFull, html, css } from './util/run' +import { run as runFull, html, css } from './util/run' function run(input, opts = {}) { return postcss([ @@ -15,1404 +15,1399 @@ function run(input, opts = {}) { ]).process(input, { from: undefined }) } -crosscheck(({ stable, oxide }) => { - test('it looks up values in the theme using dot notation', () => { - let input = css` - .banana { - color: theme('colors.yellow'); - } - ` - - let output = css` - .banana { - color: #f7cc50; - } - ` - - return run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('it looks up values in the theme using bracket notation', () => { - let input = css` - .banana { - color: theme('colors[yellow]'); - } - ` - - let output = css` - .banana { - color: #f7cc50; - } - ` - - return run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('it looks up values in the theme using consecutive bracket notation', () => { - let input = css` - .banana { - color: theme('colors[yellow][100]'); - } - ` - - let output = css` - .banana { - color: #f7cc50; - } - ` - - return run(input, { - theme: { - colors: { - yellow: { - 100: '#f7cc50', - }, - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('it looks up values in the theme using bracket notation that have dots in them', () => { - let input = css` - .banana { - padding-top: theme('spacing[1.5]'); - } - ` - - let output = css` - .banana { - padding-top: 0.375rem; - } - ` - - return run(input, { - theme: { - spacing: { - '1.5': '0.375rem', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('theme with mismatched brackets throws an error ', async () => { - let config = { - theme: { - spacing: { - '1.5': '0.375rem', - }, - }, +test('it looks up values in the theme using dot notation', () => { + let input = css` + .banana { + color: theme('colors.yellow'); } + ` - let input = (path) => css` - .banana { - padding-top: theme('${path}'); - } - ` + let output = css` + .banana { + color: #f7cc50; + } + ` - await expect(run(input('spacing[1.5]]'), config)).rejects.toThrowError( - `Path is invalid. Has unbalanced brackets: spacing[1.5]]` - ) - - await expect(run(input('spacing[[1.5]'), config)).rejects.toThrowError( - `Path is invalid. Has unbalanced brackets: spacing[[1.5]` - ) - - await expect(run(input('spacing[a['), config)).rejects.toThrowError( - `Path is invalid. Has unbalanced brackets: spacing[a[` - ) - }) - - test('color can be a function', () => { - let input = css` - .backgroundColor { - color: theme('backgroundColor.fn'); - } - .borderColor { - color: theme('borderColor.fn'); - } - .caretColor { - color: theme('caretColor.fn'); - } - .colors { - color: theme('colors.fn'); - } - .divideColor { - color: theme('divideColor.fn'); - } - .fill { - color: theme('fill.fn'); - } - .gradientColorStops { - color: theme('gradientColorStops.fn'); - } - .placeholderColor { - color: theme('placeholderColor.fn'); - } - .ringColor { - color: theme('ringColor.fn'); - } - .ringOffsetColor { - color: theme('ringOffsetColor.fn'); - } - .stroke { - color: theme('stroke.fn'); - } - .textColor { - color: theme('textColor.fn'); - } - ` - - let output = css` - .backgroundColor { - color: #f00; - } - .borderColor { - color: #f00; - } - .caretColor { - color: #f00; - } - .colors { - color: #f00; - } - .divideColor { - color: #f00; - } - .fill { - color: #f00; - } - .gradientColorStops { - color: #f00; - } - .placeholderColor { - color: #f00; - } - .ringColor { - color: #f00; - } - .ringOffsetColor { - color: #f00; - } - .stroke { - color: #f00; - } - .textColor { - color: #f00; - } - ` - - let fn = () => `#f00` - - return run(input, { - theme: { - backgroundColor: { fn }, - borderColor: { fn }, - caretColor: { fn }, - colors: { fn }, - divideColor: { fn }, - fill: { fn }, - gradientColorStops: { fn }, - placeholderColor: { fn }, - ringColor: { fn }, - ringOffsetColor: { fn }, - stroke: { fn }, - textColor: { fn }, + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) }) +}) - test('quotes are optional around the lookup path', () => { - let input = css` - .banana { - color: theme(colors.yellow); - } - ` +test('it looks up values in the theme using bracket notation', () => { + let input = css` + .banana { + color: theme('colors[yellow]'); + } + ` - let output = css` - .banana { - color: #f7cc50; - } - ` + let output = css` + .banana { + color: #f7cc50; + } + ` - return run(input, { + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('it looks up values in the theme using consecutive bracket notation', () => { + let input = css` + .banana { + color: theme('colors[yellow][100]'); + } + ` + + let output = css` + .banana { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: { + 100: '#f7cc50', + }, + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('it looks up values in the theme using bracket notation that have dots in them', () => { + let input = css` + .banana { + padding-top: theme('spacing[1.5]'); + } + ` + + let output = css` + .banana { + padding-top: 0.375rem; + } + ` + + return run(input, { + theme: { + spacing: { + '1.5': '0.375rem', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('theme with mismatched brackets throws an error ', async () => { + let config = { + theme: { + spacing: { + '1.5': '0.375rem', + }, + }, + } + + let input = (path) => css` + .banana { + padding-top: theme('${path}'); + } + ` + + await expect(run(input('spacing[1.5]]'), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[1.5]]` + ) + + await expect(run(input('spacing[[1.5]'), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[[1.5]` + ) + + await expect(run(input('spacing[a['), config)).rejects.toThrowError( + `Path is invalid. Has unbalanced brackets: spacing[a[` + ) +}) + +test('color can be a function', () => { + let input = css` + .backgroundColor { + color: theme('backgroundColor.fn'); + } + .borderColor { + color: theme('borderColor.fn'); + } + .caretColor { + color: theme('caretColor.fn'); + } + .colors { + color: theme('colors.fn'); + } + .divideColor { + color: theme('divideColor.fn'); + } + .fill { + color: theme('fill.fn'); + } + .gradientColorStops { + color: theme('gradientColorStops.fn'); + } + .placeholderColor { + color: theme('placeholderColor.fn'); + } + .ringColor { + color: theme('ringColor.fn'); + } + .ringOffsetColor { + color: theme('ringOffsetColor.fn'); + } + .stroke { + color: theme('stroke.fn'); + } + .textColor { + color: theme('textColor.fn'); + } + ` + + let output = css` + .backgroundColor { + color: #f00; + } + .borderColor { + color: #f00; + } + .caretColor { + color: #f00; + } + .colors { + color: #f00; + } + .divideColor { + color: #f00; + } + .fill { + color: #f00; + } + .gradientColorStops { + color: #f00; + } + .placeholderColor { + color: #f00; + } + .ringColor { + color: #f00; + } + .ringOffsetColor { + color: #f00; + } + .stroke { + color: #f00; + } + .textColor { + color: #f00; + } + ` + + let fn = () => `#f00` + + return run(input, { + theme: { + backgroundColor: { fn }, + borderColor: { fn }, + caretColor: { fn }, + colors: { fn }, + divideColor: { fn }, + fill: { fn }, + gradientColorStops: { fn }, + placeholderColor: { fn }, + ringColor: { fn }, + ringOffsetColor: { fn }, + stroke: { fn }, + textColor: { fn }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('quotes are optional around the lookup path', () => { + let input = css` + .banana { + color: theme(colors.yellow); + } + ` + + let output = css` + .banana { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('a default value can be provided', () => { + let input = css` + .cookieMonster { + color: theme('colors.blue', #0000ff); + } + ` + + let output = css` + .cookieMonster { + color: #0000ff; + } + ` + + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('the default value can use the theme function', () => { + let input = css` + .cookieMonster { + color: theme('colors.blue', theme('colors.yellow')); + } + ` + + let output = css` + .cookieMonster { + color: #f7cc50; + } + ` + + return run(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('quotes are preserved around default values', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans', 'Helvetica Neue'); + } + ` + + let output = css` + .heading { + font-family: 'Helvetica Neue'; + } + ` + + return run(input, { + theme: { + fontFamily: { + serif: 'Constantia', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('an unquoted list is valid as a default value', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans', Helvetica, Arial, sans-serif); + } + ` + + let output = css` + .heading { + font-family: Helvetica, Arial, sans-serif; + } + ` + + return run(input, { + theme: { + fontFamily: { + serif: 'Constantia', + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('a missing root theme value throws', () => { + let input = css` + .heading { + color: theme('colours.gray.100'); + } + ` + + return expect( + run(input, { theme: { colors: { yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError( + `'colours.gray.100' does not exist in your theme config. Your theme has the following top-level keys: 'colors'` + ) +}) - test('a default value can be provided', () => { - let input = css` - .cookieMonster { - color: theme('colors.blue', #0000ff); - } - ` +test('a missing nested theme property throws', () => { + let input = css` + .heading { + color: theme('colors.red'); + } + ` - let output = css` - .cookieMonster { - color: #0000ff; - } - ` + return expect( + run(input, { + theme: { + colors: { + blue: 'blue', + yellow: '#f7cc50', + }, + }, + }) + ).rejects.toThrowError( + `'colors.red' does not exist in your theme config. 'colors' has the following valid keys: 'blue', 'yellow'` + ) +}) - return run(input, { +test('a missing nested theme property with a close alternative throws with a suggestion', () => { + let input = css` + .heading { + color: theme('colors.yellw'); + } + ` + + return expect( + run(input, { theme: { colors: { yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError( + `'colors.yellw' does not exist in your theme config. Did you mean 'colors.yellow'?` + ) +}) - test('the default value can use the theme function', () => { - let input = css` - .cookieMonster { - color: theme('colors.blue', theme('colors.yellow')); - } - ` +test('a path through a non-object throws', () => { + let input = css` + .heading { + color: theme('colors.yellow.100'); + } + ` - let output = css` - .cookieMonster { - color: #f7cc50; - } - ` - - return run(input, { + return expect( + run(input, { theme: { colors: { yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) }) - }) - - test('quotes are preserved around default values', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans', 'Helvetica Neue'); - } - ` - - let output = css` - .heading { - font-family: 'Helvetica Neue'; - } - ` - - return run(input, { - theme: { - fontFamily: { - serif: 'Constantia', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('an unquoted list is valid as a default value', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans', Helvetica, Arial, sans-serif); - } - ` - - let output = css` - .heading { - font-family: Helvetica, Arial, sans-serif; - } - ` - - return run(input, { - theme: { - fontFamily: { - serif: 'Constantia', - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('a missing root theme value throws', () => { - let input = css` - .heading { - color: theme('colours.gray.100'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colours.gray.100' does not exist in your theme config. Your theme has the following top-level keys: 'colors'` - ) - }) - - test('a missing nested theme property throws', () => { - let input = css` - .heading { - color: theme('colors.red'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - blue: 'blue', - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors.red' does not exist in your theme config. 'colors' has the following valid keys: 'blue', 'yellow'` - ) - }) - - test('a missing nested theme property with a close alternative throws with a suggestion', () => { - let input = css` - .heading { - color: theme('colors.yellw'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors.yellw' does not exist in your theme config. Did you mean 'colors.yellow'?` - ) - }) - - test('a path through a non-object throws', () => { - let input = css` - .heading { - color: theme('colors.yellow.100'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors.yellow.100' does not exist in your theme config. 'colors.yellow' is not an object.` - ) - }) - - test('a path which exists but is not a string throws', () => { - let input = css` - .heading { - color: theme('colors.yellow'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: Symbol(), - }, - }, - }) - ).rejects.toThrowError(`'colors.yellow' was found but does not resolve to a string.`) - }) - - test('a path which exists but is invalid throws', () => { - let input = css` - .heading { - color: theme('colors'); - } - ` - - return expect( - run(input, { - theme: { - colors: {}, - }, - }) - ).rejects.toThrowError(`'colors' was found but does not resolve to a string.`) - }) - - test('a path which is an object throws with a suggested key', () => { - let input = css` - .heading { - color: theme('colors'); - } - ` - - return expect( - run(input, { - theme: { - colors: { - yellow: '#f7cc50', - }, - }, - }) - ).rejects.toThrowError( - `'colors' was found but does not resolve to a string. Did you mean something like 'colors.yellow'?` - ) - }) - - test('array values are joined by default', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans'); - } - ` - - let output = css` - .heading { - font-family: Inter, Helvetica, sans-serif; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', 'Helvetica', 'sans-serif'], - }, - }, - }).then((result) => { - expect(result.css).toEqual(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font sizes are retrieved without default line-heights or letter-spacing', () => { - let input = css` - .heading-1 { - font-size: theme('fontSize.lg'); - } - .heading-2 { - font-size: theme('fontSize.xl'); - } - ` - - let output = css` - .heading-1 { - font-size: 20px; - } - .heading-2 { - font-size: 24px; - } - ` - - return run(input, { - theme: { - fontSize: { - lg: ['20px', '28px'], - xl: ['24px', { lineHeight: '32px', letterSpacing: '-0.01em' }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('outlines are retrieved without default outline-offset', () => { - let input = css` - .element { - outline: theme('outline.black'); - } - ` - - let output = css` - .element { - outline: 2px dotted #000; - } - ` - - return run(input, { - theme: { - outline: { - black: ['2px dotted black', '4px'], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-family values are retrieved without font-variation-settings', () => { - let input = css` - .heading-1 { - font-family: theme('fontFamily.sans'); - } - .heading-2 { - font-family: theme('fontFamily.serif'); - } - .heading-3 { - font-family: theme('fontFamily.mono'); - } - ` - - let output = css` - .heading-1 { - font-family: Inter; - } - .heading-2 { - font-family: Times, serif; - } - .heading-3 { - font-family: Menlo, monospace; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontVariationSettings: '"opsz" 32' }], - serif: [['Times', 'serif'], { fontVariationSettings: '"opsz" 32' }], - mono: ['Menlo, monospace', { fontVariationSettings: '"opsz" 32' }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-variation-settings values can be retrieved', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans'); - font-variation-settings: theme('fontFamily.sans[1].fontVariationSettings'); - } - ` - - let output = css` - .heading { - font-family: Inter; - font-variation-settings: 'opsz' 32; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontVariationSettings: "'opsz' 32" }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-family values are joined when an array', () => { - let input = css` - .element { - font-family: theme('fontFamily.sans'); - } - ` - - let output = css` - .element { - font-family: Helvetica, Arial, sans-serif; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Helvetica', 'Arial', 'sans-serif'], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-family values are retrieved without font-feature-settings', () => { - let input = css` - .heading-1 { - font-family: theme('fontFamily.sans'); - } - .heading-2 { - font-family: theme('fontFamily.serif'); - } - .heading-3 { - font-family: theme('fontFamily.mono'); - } - ` - - let output = css` - .heading-1 { - font-family: Inter; - } - .heading-2 { - font-family: Times, serif; - } - .heading-3 { - font-family: Menlo, monospace; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontFeatureSettings: '"cv11"' }], - serif: [['Times', 'serif'], { fontFeatureSettings: '"cv11"' }], - mono: ['Menlo, monospace', { fontFeatureSettings: '"cv11"' }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('font-feature-settings values can be retrieved', () => { - let input = css` - .heading { - font-family: theme('fontFamily.sans'); - font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings'); - } - ` - - let output = css` - .heading { - font-feature-settings: 'cv11'; - font-family: Inter; - } - ` - - return run(input, { - theme: { - fontFamily: { - sans: ['Inter', { fontFeatureSettings: "'cv11'" }], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('box-shadow values are joined when an array', () => { - let input = css` - .element { - box-shadow: theme('boxShadow.wtf'); - } - ` - - let output = css` - .element { - box-shadow: 0 0 2px #000, 1px 2px 3px #fff; - } - ` - - return run(input, { - theme: { - boxShadow: { - wtf: ['0 0 2px black', '1px 2px 3px white'], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('transition-property values are joined when an array', () => { - let input = css` - .element { - transition-property: theme('transitionProperty.colors'); - } - ` - - let output = css` - .element { - transition-property: color, fill; - } - ` - - return run(input, { - theme: { - transitionProperty: { - colors: ['color', 'fill'], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('transition-duration values are joined when an array', () => { - let input = css` - .element { - transition-duration: theme('transitionDuration.lol'); - } - ` - - let output = css` - .element { - transition-duration: 1s, 2s; - } - ` - - return run(input, { - theme: { - transitionDuration: { - lol: ['1s', '2s'], - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('basic screen function calls are expanded', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } - } - ` - - let output = css` - @media (min-width: 600px) { - .foo { - color: red; - } - } - ` - - return run(input, { - theme: { screens: { sm: '600px' } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('screen function supports max-width screens', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } - } - ` - - let output = css` - @media (max-width: 600px) { - .foo { - color: red; - } - } - ` - - return run(input, { - theme: { screens: { sm: { max: '600px' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('screen function supports min-width screens', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } - } - ` - - let output = css` - @media (min-width: 600px) { - .foo { - color: red; - } - } - ` - - return run(input, { - theme: { screens: { sm: { min: '600px' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('screen function supports min-width and max-width screens', () => { - let input = css` - @media screen(sm) { - .foo { - color: red; - } - } - ` - - let output = css` - @media (min-width: 600px) and (max-width: 700px) { - .foo { - color: red; - } - } - ` - - return run(input, { - theme: { screens: { sm: { min: '600px', max: '700px' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('screen function supports raw screens', () => { - let input = css` - @media screen(mono) { - .foo { - color: red; - } - } - ` - - let output = css` - @media monochrome { - .foo { - color: red; - } - } - ` - - return run(input, { - theme: { screens: { mono: { raw: 'monochrome' } } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('screen arguments can be quoted', () => { - let input = css` - @media screen('sm') { - .foo { - color: red; - } - } - ` - - let output = css` - @media (min-width: 600px) { - .foo { - color: red; - } - } - ` - - return run(input, { - theme: { screens: { sm: '600px' } }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function can extract alpha values for colors (1)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / 50%); - } - ` - - let output = css` - .foo { - color: #3b82f680; - } - ` - - return run(input, { - theme: { - colors: { blue: { 500: '#3b82f6' } }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function can extract alpha values for colors (2)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / 0.5); - } - ` - - let output = css` - .foo { - color: #3b82f680; - } - ` - - return run(input, { - theme: { - colors: { blue: { 500: '#3b82f6' } }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function can extract alpha values for colors (3)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / var(--my-alpha)); - } - ` - - let output = css` - .foo { - color: rgb(59 130 246 / var(--my-alpha)); - } - ` - - return run(input, { - theme: { - colors: { blue: { 500: '#3b82f6' } }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function can extract alpha values for colors (4)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / 50%); - } - ` - - let output = css` - .foo { - color: #3c83f680; - } - ` - - return run(input, { + ).rejects.toThrowError( + `'colors.yellow.100' does not exist in your theme config. 'colors.yellow' is not an object.` + ) +}) + +test('a path which exists but is not a string throws', () => { + let input = css` + .heading { + color: theme('colors.yellow'); + } + ` + + return expect( + run(input, { theme: { colors: { - blue: { 500: 'hsl(217, 91%, 60%)' }, + yellow: Symbol(), }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError(`'colors.yellow' was found but does not resolve to a string.`) +}) - test('Theme function can extract alpha values for colors (5)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / 0.5); - } - ` +test('a path which exists but is invalid throws', () => { + let input = css` + .heading { + color: theme('colors'); + } + ` - let output = css` - .foo { - color: #3c83f680; - } - ` - - return run(input, { + return expect( + run(input, { theme: { - colors: { - blue: { 500: 'hsl(217, 91%, 60%)' }, - }, + colors: {}, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) }) - }) + ).rejects.toThrowError(`'colors' was found but does not resolve to a string.`) +}) - test('Theme function can extract alpha values for colors (6)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / var(--my-alpha)); - } - ` +test('a path which is an object throws with a suggested key', () => { + let input = css` + .heading { + color: theme('colors'); + } + ` - let output = css` - .foo { - color: hsl(217 91% 60% / var(--my-alpha)); - } - ` - - return run(input, { - theme: { - colors: { - blue: { 500: 'hsl(217, 91%, 60%)' }, - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function can extract alpha values for colors (7)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / var(--my-alpha)); - } - ` - - let output = css` - .foo { - color: rgb(var(--foo) / var(--my-alpha)); - } - ` - - return runFull(input, { - theme: { - colors: { - blue: { - 500: 'rgb(var(--foo) / )', - }, - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function can extract alpha values for colors (8)', () => { - let input = css` - .foo { - color: theme(colors.blue.500 / theme(opacity.myalpha)); - } - ` - - let output = css` - .foo { - color: rgb(var(--foo) / 50%); - } - ` - - return runFull(input, { - theme: { - colors: { - blue: { - 500: 'rgb(var(--foo) / )', - }, - }, - - opacity: { - myalpha: '50%', - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme functions replace the alpha value placeholder even with no alpha provided', () => { - let input = css` - .foo { - background: theme(colors.blue.400); - color: theme(colors.blue.500); - } - ` - - let output = css` - .foo { - color: rgb(var(--foo) / 1); - background: #00f; - } - ` - - return runFull(input, { - theme: { - colors: { - blue: { - 400: 'rgb(0 0 255 / )', - 500: 'rgb(var(--foo) / )', - }, - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme functions can reference values with slashes in brackets', () => { - let input = css` - .foo1 { - color: theme(colors[a/b]); - } - .foo2 { - color: theme(colors[a/b]/50%); - } - ` - - let output = css` - .foo1 { - color: #000; - } - .foo2 { - color: #00000080; - } - ` - - return runFull(input, { - theme: { - colors: { - 'a/b': '#000000', - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme functions with alpha value inside quotes', () => { - let input = css` - .foo { - color: theme('colors.yellow / 50%'); - } - ` - - let output = css` - .foo { - color: #f7cc5080; - } - ` - - return runFull(input, { + return expect( + run(input, { theme: { colors: { yellow: '#f7cc50', }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) }) + ).rejects.toThrowError( + `'colors' was found but does not resolve to a string. Did you mean something like 'colors.yellow'?` + ) +}) + +test('array values are joined by default', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans'); + } + ` + + let output = css` + .heading { + font-family: Inter, Helvetica, sans-serif; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', 'Helvetica', 'sans-serif'], + }, + }, + }).then((result) => { + expect(result.css).toEqual(output) + expect(result.warnings().length).toBe(0) }) +}) - test('Theme functions with alpha with quotes value around color only', () => { - let input = css` +test('font sizes are retrieved without default line-heights or letter-spacing', () => { + let input = css` + .heading-1 { + font-size: theme('fontSize.lg'); + } + .heading-2 { + font-size: theme('fontSize.xl'); + } + ` + + let output = css` + .heading-1 { + font-size: 20px; + } + .heading-2 { + font-size: 24px; + } + ` + + return run(input, { + theme: { + fontSize: { + lg: ['20px', '28px'], + xl: ['24px', { lineHeight: '32px', letterSpacing: '-0.01em' }], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('outlines are retrieved without default outline-offset', () => { + let input = css` + .element { + outline: theme('outline.black'); + } + ` + + let output = css` + .element { + outline: 2px dotted #000; + } + ` + + return run(input, { + theme: { + outline: { + black: ['2px dotted black', '4px'], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-family values are retrieved without font-variation-settings', () => { + let input = css` + .heading-1 { + font-family: theme('fontFamily.sans'); + } + .heading-2 { + font-family: theme('fontFamily.serif'); + } + .heading-3 { + font-family: theme('fontFamily.mono'); + } + ` + + let output = css` + .heading-1 { + font-family: Inter; + } + .heading-2 { + font-family: Times, serif; + } + .heading-3 { + font-family: Menlo, monospace; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontVariationSettings: '"opsz" 32' }], + serif: [['Times', 'serif'], { fontVariationSettings: '"opsz" 32' }], + mono: ['Menlo, monospace', { fontVariationSettings: '"opsz" 32' }], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-variation-settings values can be retrieved', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans'); + font-variation-settings: theme('fontFamily.sans[1].fontVariationSettings'); + } + ` + + let output = css` + .heading { + font-family: Inter; + font-variation-settings: 'opsz' 32; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontVariationSettings: "'opsz' 32" }], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-family values are joined when an array', () => { + let input = css` + .element { + font-family: theme('fontFamily.sans'); + } + ` + + let output = css` + .element { + font-family: Helvetica, Arial, sans-serif; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Helvetica', 'Arial', 'sans-serif'], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-family values are retrieved without font-feature-settings', () => { + let input = css` + .heading-1 { + font-family: theme('fontFamily.sans'); + } + .heading-2 { + font-family: theme('fontFamily.serif'); + } + .heading-3 { + font-family: theme('fontFamily.mono'); + } + ` + + let output = css` + .heading-1 { + font-family: Inter; + } + .heading-2 { + font-family: Times, serif; + } + .heading-3 { + font-family: Menlo, monospace; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontFeatureSettings: '"cv11"' }], + serif: [['Times', 'serif'], { fontFeatureSettings: '"cv11"' }], + mono: ['Menlo, monospace', { fontFeatureSettings: '"cv11"' }], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('font-feature-settings values can be retrieved', () => { + let input = css` + .heading { + font-family: theme('fontFamily.sans'); + font-feature-settings: theme('fontFamily.sans[1].fontFeatureSettings'); + } + ` + + let output = css` + .heading { + font-feature-settings: 'cv11'; + font-family: Inter; + } + ` + + return run(input, { + theme: { + fontFamily: { + sans: ['Inter', { fontFeatureSettings: "'cv11'" }], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('box-shadow values are joined when an array', () => { + let input = css` + .element { + box-shadow: theme('boxShadow.wtf'); + } + ` + + let output = css` + .element { + box-shadow: 0 0 2px #000, 1px 2px 3px #fff; + } + ` + + return run(input, { + theme: { + boxShadow: { + wtf: ['0 0 2px black', '1px 2px 3px white'], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('transition-property values are joined when an array', () => { + let input = css` + .element { + transition-property: theme('transitionProperty.colors'); + } + ` + + let output = css` + .element { + transition-property: color, fill; + } + ` + + return run(input, { + theme: { + transitionProperty: { + colors: ['color', 'fill'], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('transition-duration values are joined when an array', () => { + let input = css` + .element { + transition-duration: theme('transitionDuration.lol'); + } + ` + + let output = css` + .element { + transition-duration: 1s, 2s; + } + ` + + return run(input, { + theme: { + transitionDuration: { + lol: ['1s', '2s'], + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('basic screen function calls are expanded', () => { + let input = css` + @media screen(sm) { .foo { - color: theme('colors.yellow' / 50%); + color: red; } - ` + } + ` - let output = css` + let output = css` + @media (min-width: 600px) { .foo { - color: #f7cc5080; + color: red; } - ` + } + ` - return runFull(input, { - theme: { - colors: { - yellow: '#f7cc50', + return run(input, { + theme: { screens: { sm: '600px' } }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('screen function supports max-width screens', () => { + let input = css` + @media screen(sm) { + .foo { + color: red; + } + } + ` + + let output = css` + @media (max-width: 600px) { + .foo { + color: red; + } + } + ` + + return run(input, { + theme: { screens: { sm: { max: '600px' } } }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('screen function supports min-width screens', () => { + let input = css` + @media screen(sm) { + .foo { + color: red; + } + } + ` + + let output = css` + @media (min-width: 600px) { + .foo { + color: red; + } + } + ` + + return run(input, { + theme: { screens: { sm: { min: '600px' } } }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('screen function supports min-width and max-width screens', () => { + let input = css` + @media screen(sm) { + .foo { + color: red; + } + } + ` + + let output = css` + @media (min-width: 600px) and (max-width: 700px) { + .foo { + color: red; + } + } + ` + + return run(input, { + theme: { screens: { sm: { min: '600px', max: '700px' } } }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('screen function supports raw screens', () => { + let input = css` + @media screen(mono) { + .foo { + color: red; + } + } + ` + + let output = css` + @media monochrome { + .foo { + color: red; + } + } + ` + + return run(input, { + theme: { screens: { mono: { raw: 'monochrome' } } }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('screen arguments can be quoted', () => { + let input = css` + @media screen('sm') { + .foo { + color: red; + } + } + ` + + let output = css` + @media (min-width: 600px) { + .foo { + color: red; + } + } + ` + + return run(input, { + theme: { screens: { sm: '600px' } }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (1)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 50%); + } + ` + + let output = css` + .foo { + color: #3b82f680; + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (2)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 0.5); + } + ` + + let output = css` + .foo { + color: #3b82f680; + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (3)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` + + let output = css` + .foo { + color: rgb(59 130 246 / var(--my-alpha)); + } + ` + + return run(input, { + theme: { + colors: { blue: { 500: '#3b82f6' } }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (4)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 50%); + } + ` + + let output = css` + .foo { + color: #3c83f680; + } + ` + + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (5)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / 0.5); + } + ` + + let output = css` + .foo { + color: #3c83f680; + } + ` + + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (6)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` + + let output = css` + .foo { + color: hsl(217 91% 60% / var(--my-alpha)); + } + ` + + return run(input, { + theme: { + colors: { + blue: { 500: 'hsl(217, 91%, 60%)' }, + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function can extract alpha values for colors (7)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / var(--my-alpha)); + } + ` + + let output = css` + .foo { + color: rgb(var(--foo) / var(--my-alpha)); + } + ` + + return runFull(input, { + theme: { + colors: { + blue: { + 500: 'rgb(var(--foo) / )', }, }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) }) +}) - it('can find values with slashes in the theme key while still allowing for alpha values ', () => { - let input = css` +test('Theme function can extract alpha values for colors (8)', () => { + let input = css` + .foo { + color: theme(colors.blue.500 / theme(opacity.myalpha)); + } + ` + + let output = css` + .foo { + color: rgb(var(--foo) / 50%); + } + ` + + return runFull(input, { + theme: { + colors: { + blue: { + 500: 'rgb(var(--foo) / )', + }, + }, + + opacity: { + myalpha: '50%', + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme functions replace the alpha value placeholder even with no alpha provided', () => { + let input = css` + .foo { + background: theme(colors.blue.400); + color: theme(colors.blue.500); + } + ` + + let output = css` + .foo { + color: rgb(var(--foo) / 1); + background: #00f; + } + ` + + return runFull(input, { + theme: { + colors: { + blue: { + 400: 'rgb(0 0 255 / )', + 500: 'rgb(var(--foo) / )', + }, + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme functions can reference values with slashes in brackets', () => { + let input = css` + .foo1 { + color: theme(colors[a/b]); + } + .foo2 { + color: theme(colors[a/b]/50%); + } + ` + + let output = css` + .foo1 { + color: #000; + } + .foo2 { + color: #00000080; + } + ` + + return runFull(input, { + theme: { + colors: { + 'a/b': '#000000', + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme functions with alpha value inside quotes', () => { + let input = css` + .foo { + color: theme('colors.yellow / 50%'); + } + ` + + let output = css` + .foo { + color: #f7cc5080; + } + ` + + return runFull(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme functions with alpha with quotes value around color only', () => { + let input = css` + .foo { + color: theme('colors.yellow' / 50%); + } + ` + + let output = css` + .foo { + color: #f7cc5080; + } + ` + + return runFull(input, { + theme: { + colors: { + yellow: '#f7cc50', + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +it('can find values with slashes in the theme key while still allowing for alpha values ', () => { + let input = css` + .foo00 { + color: theme(colors.foo-5); + } + .foo01 { + color: theme(colors.foo-5/10); + } + .foo02 { + color: theme(colors.foo-5/10/25); + } + .foo03 { + color: theme(colors.foo-5 / 10); + } + .foo04 { + color: theme(colors.foo-5/10 / 25); + } + ` + + return runFull(input, { + theme: { + colors: { + 'foo-5': '#050000', + 'foo-5/10': '#051000', + 'foo-5/10/25': '#051025', + }, + }, + }).then((result) => { + expect(result.css).toMatchCss(css` .foo00 { - color: theme(colors.foo-5); + color: #050000; } .foo01 { - color: theme(colors.foo-5/10); + color: #051000; } .foo02 { - color: theme(colors.foo-5/10/25); + color: #051025; } .foo03 { - color: theme(colors.foo-5 / 10); + color: #050000; } .foo04 { - color: theme(colors.foo-5/10 / 25); + color: #051000; + } + `) + }) +}) + +describe('context dependent', () => { + let configPath = path.resolve(__dirname, './evaluate-tailwind-functions.tailwind.config.js') + let filePath = path.resolve(__dirname, './evaluate-tailwind-functions.test.html') + let config = { + content: [filePath], + corePlugins: { preflight: false }, + } + + // Rebuild the config file for each test + beforeEach(() => fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`)) + afterEach(() => fs.promises.unlink(configPath)) + + test('should not generate when theme fn doesnt resolve', async () => { + await fs.promises.writeFile( + filePath, + html` +
+
+ ` + ) + + // TODO: We need a way to reuse the context in our test suite without requiring writing to files + // It should be an explicit thing tho — like we create a context and pass it in or something + let result = await runFull('@tailwind utilities', configPath) + + // 1. On first run it should work because it's been removed from the class cache + expect(result.css).toMatchCss(css` + .underline { + text-decoration-line: underline; + } + `) + + // 2. But we get a warning in the console + expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) + + // 3. The second run should work fine because it's been removed from the class cache + result = await runFull('@tailwind utilities', configPath) + + expect(result.css).toMatchCss(css` + .underline { + text-decoration-line: underline; + } + `) + + // 4. But we've not received any further logs about it + expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) + }) + + test('it works mayhaps', async () => { + let input = css` + .test { + /* prettier-ignore */ + inset: calc(-1 * (2*theme("spacing.4"))); + /* prettier-ignore */ + padding: calc(-1 * (2* theme("spacing.4"))); } ` - return runFull(input, { + let output = css` + .test { + /* prettier-ignore */ + inset: calc(-1 * (2*1rem)); + /* prettier-ignore */ + padding: calc(-1 * (2* 1rem)); + } + ` + + return run(input, { theme: { - colors: { - 'foo-5': '#050000', - 'foo-5/10': '#051000', - 'foo-5/10/25': '#051025', + spacing: { + 4: '1rem', }, }, }).then((result) => { - expect(result.css).toMatchCss(css` - .foo00 { - color: #050000; - } - .foo01 { - color: #051000; - } - .foo02 { - color: #051025; - } - .foo03 { - color: #050000; - } - .foo04 { - color: #051000; - } - `) - }) - }) - - describe('context dependent', () => { - let configPath = path.resolve(__dirname, './evaluate-tailwind-functions.tailwind.config.js') - let filePath = path.resolve(__dirname, './evaluate-tailwind-functions.test.html') - let config = { - content: [filePath], - corePlugins: { preflight: false }, - } - - // Rebuild the config file for each test - beforeEach(() => - fs.promises.writeFile(configPath, `module.exports = ${JSON.stringify(config)};`) - ) - afterEach(() => fs.promises.unlink(configPath)) - - oxide.test.todo('should not generate when theme fn doesnt resolve') - stable.test('should not generate when theme fn doesnt resolve', async () => { - await fs.promises.writeFile( - filePath, - html` -
-
- ` - ) - - // TODO: We need a way to reuse the context in our test suite without requiring writing to files - // It should be an explicit thing tho — like we create a context and pass it in or something - let result = await runFull('@tailwind utilities', configPath) - - // 1. On first run it should work because it's been removed from the class cache - expect(result.css).toMatchCss(css` - .underline { - text-decoration-line: underline; - } - `) - - // 2. But we get a warning in the console - expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) - - // 3. The second run should work fine because it's been removed from the class cache - result = await runFull('@tailwind utilities', configPath) - - expect(result.css).toMatchCss(css` - .underline { - text-decoration-line: underline; - } - `) - - // 4. But we've not received any further logs about it - expect().toHaveBeenWarnedWith(['invalid-theme-key-in-class']) - }) - - test('it works mayhaps', async () => { - let input = css` - .test { - /* prettier-ignore */ - inset: calc(-1 * (2*theme("spacing.4"))); - /* prettier-ignore */ - padding: calc(-1 * (2* theme("spacing.4"))); - } - ` - - let output = css` - .test { - /* prettier-ignore */ - inset: calc(-1 * (2*1rem)); - /* prettier-ignore */ - padding: calc(-1 * (2* 1rem)); - } - ` - - return run(input, { - theme: { - spacing: { - 4: '1rem', - }, - }, - }).then((result) => { - expect(result.css).toMatchCss(output) - expect(result.warnings().length).toBe(0) - }) + expect(result.css).toMatchCss(output) + expect(result.warnings().length).toBe(0) }) }) }) diff --git a/tests/experimental.test.js b/tests/experimental.test.js index 3497783f9..b3fa49185 100644 --- a/tests/experimental.test.js +++ b/tests/experimental.test.js @@ -1,197 +1,195 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('experimental universal selector improvements (box-shadow)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +test('experimental universal selector improvements (box-shadow)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .resize { - resize: both; - } - .shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - test('experimental universal selector improvements (pseudo hover)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .hover\:shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .resize { - resize: both; - } - .hover\:shadow:hover { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - test('experimental universal selector improvements (multiple classes: group)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .group-hover\:shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .resize { - resize: both; - } - .group:hover .group-hover\:shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) - }) - - test('experimental universal selector improvements (child selectors: divide-y)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .resize { - resize: both; - } - .divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - `) - }) - }) - - test('experimental universal selector improvements (hover:divide-y)', () => { - let config = { - experimental: 'all', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .resize { - resize: both; - } - .hover\:divide-y:hover > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - `) - }) - }) - - test('experimental universal selector improvements (#app important)', () => { - let config = { - experimental: 'all', - important: '#app', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .shadow { - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - #app :is(.resize) { - resize: both; - } - #app :is(.divide-y > :not([hidden]) ~ :not([hidden])) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - #app :is(.shadow) { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .resize { + resize: both; + } + .shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +test('experimental universal selector improvements (pseudo hover)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .hover\:shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .resize { + resize: both; + } + .hover\:shadow:hover { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +test('experimental universal selector improvements (multiple classes: group)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .group-hover\:shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .resize { + resize: both; + } + .group:hover .group-hover\:shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) + }) +}) + +test('experimental universal selector improvements (child selectors: divide-y)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .resize { + resize: both; + } + .divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + `) + }) +}) + +test('experimental universal selector improvements (hover:divide-y)', () => { + let config = { + experimental: 'all', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .resize { + resize: both; + } + .hover\:divide-y:hover > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + `) + }) +}) + +test('experimental universal selector improvements (#app important)', () => { + let config = { + experimental: 'all', + important: '#app', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .shadow { + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + #app :is(.resize) { + resize: both; + } + #app :is(.divide-y > :not([hidden]) ~ :not([hidden])) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + #app :is(.shadow) { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + `) }) }) diff --git a/tests/extractor-edge-cases.test.js b/tests/extractor-edge-cases.test.js index 412702b35..83ca99e37 100644 --- a/tests/extractor-edge-cases.test.js +++ b/tests/extractor-edge-cases.test.js @@ -1,34 +1,32 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('PHP arrays', async () => { - let config = { - content: [ - { - raw: html`

">Hello world

`, - }, - ], - } +test('PHP arrays', async () => { + let config = { + content: [ + { + raw: html`

">Hello world

`, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .max-w-\[16rem\] { - max-width: 16rem; - } - `) - }) - }) - - test('arbitrary values with quotes', async () => { - let config = { content: [{ raw: html`
` }] } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .content-\[\'hello\]\'\] { - --tw-content: 'hello]'; - content: var(--tw-content); - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .max-w-\[16rem\] { + max-width: 16rem; + } + `) + }) +}) + +test('arbitrary values with quotes', async () => { + let config = { content: [{ raw: html`
` }] } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .content-\[\'hello\]\'\] { + --tw-content: 'hello]'; + content: var(--tw-content); + } + `) }) }) diff --git a/tests/flattenColorPalette.test.js b/tests/flattenColorPalette.test.js index dae66e806..e8edcd9aa 100644 --- a/tests/flattenColorPalette.test.js +++ b/tests/flattenColorPalette.test.js @@ -1,84 +1,81 @@ -import { crosscheck } from './util/run' import flattenColorPalette from '../src/util/flattenColorPalette' -crosscheck(() => { - test('it flattens nested color objects', () => { - expect( - flattenColorPalette({ - purple: 'purple', - white: { - 25: 'rgba(255,255,255,.25)', - 50: 'rgba(255,255,255,.5)', - 75: 'rgba(255,255,255,.75)', - DEFAULT: '#fff', - }, - red: { - 1: 'rgb(33,0,0)', - 2: 'rgb(67,0,0)', - 3: 'rgb(100,0,0)', - }, - green: { - 1: 'rgb(0,33,0)', - 2: 'rgb(0,67,0)', - 3: 'rgb(0,100,0)', - }, - blue: { - 1: 'rgb(0,0,33)', - 2: 'rgb(0,0,67)', - 3: 'rgb(0,0,100)', - }, - }) - ).toEqual({ +test('it flattens nested color objects', () => { + expect( + flattenColorPalette({ purple: 'purple', - 'white-25': 'rgba(255,255,255,.25)', - 'white-50': 'rgba(255,255,255,.5)', - 'white-75': 'rgba(255,255,255,.75)', - white: '#fff', - 'red-1': 'rgb(33,0,0)', - 'red-2': 'rgb(67,0,0)', - 'red-3': 'rgb(100,0,0)', - 'green-1': 'rgb(0,33,0)', - 'green-2': 'rgb(0,67,0)', - 'green-3': 'rgb(0,100,0)', - 'blue-1': 'rgb(0,0,33)', - 'blue-2': 'rgb(0,0,67)', - 'blue-3': 'rgb(0,0,100)', + white: { + 25: 'rgba(255,255,255,.25)', + 50: 'rgba(255,255,255,.5)', + 75: 'rgba(255,255,255,.75)', + DEFAULT: '#fff', + }, + red: { + 1: 'rgb(33,0,0)', + 2: 'rgb(67,0,0)', + 3: 'rgb(100,0,0)', + }, + green: { + 1: 'rgb(0,33,0)', + 2: 'rgb(0,67,0)', + 3: 'rgb(0,100,0)', + }, + blue: { + 1: 'rgb(0,0,33)', + 2: 'rgb(0,0,67)', + 3: 'rgb(0,0,100)', + }, }) - }) - - test('it flattens deeply nested color objects', () => { - expect( - flattenColorPalette({ - primary: 'purple', - secondary: { - DEFAULT: 'blue', - hover: 'cyan', - focus: 'red', - }, - button: { - primary: { - DEFAULT: 'magenta', - hover: 'green', - focus: { - DEFAULT: 'yellow', - variant: 'orange', - }, - }, - }, - }) - ).toEqual({ - primary: 'purple', - secondary: 'blue', - 'secondary-hover': 'cyan', - 'secondary-focus': 'red', - 'button-primary': 'magenta', - 'button-primary-hover': 'green', - 'button-primary-focus': 'yellow', - 'button-primary-focus-variant': 'orange', - }) - }) - - test('it handles empty objects', () => { - expect(flattenColorPalette({})).toEqual({}) + ).toEqual({ + purple: 'purple', + 'white-25': 'rgba(255,255,255,.25)', + 'white-50': 'rgba(255,255,255,.5)', + 'white-75': 'rgba(255,255,255,.75)', + white: '#fff', + 'red-1': 'rgb(33,0,0)', + 'red-2': 'rgb(67,0,0)', + 'red-3': 'rgb(100,0,0)', + 'green-1': 'rgb(0,33,0)', + 'green-2': 'rgb(0,67,0)', + 'green-3': 'rgb(0,100,0)', + 'blue-1': 'rgb(0,0,33)', + 'blue-2': 'rgb(0,0,67)', + 'blue-3': 'rgb(0,0,100)', }) }) + +test('it flattens deeply nested color objects', () => { + expect( + flattenColorPalette({ + primary: 'purple', + secondary: { + DEFAULT: 'blue', + hover: 'cyan', + focus: 'red', + }, + button: { + primary: { + DEFAULT: 'magenta', + hover: 'green', + focus: { + DEFAULT: 'yellow', + variant: 'orange', + }, + }, + }, + }) + ).toEqual({ + primary: 'purple', + secondary: 'blue', + 'secondary-hover': 'cyan', + 'secondary-focus': 'red', + 'button-primary': 'magenta', + 'button-primary-hover': 'green', + 'button-primary-focus': 'yellow', + 'button-primary-focus-variant': 'orange', + }) +}) + +test('it handles empty objects', () => { + expect(flattenColorPalette({})).toEqual({}) +}) diff --git a/tests/format-variant-selector.test.js b/tests/format-variant-selector.test.js index 9a53f3aac..3873f5d2d 100644 --- a/tests/format-variant-selector.test.js +++ b/tests/format-variant-selector.test.js @@ -1,367 +1,364 @@ import { finalizeSelector } from '../src/util/formatVariantSelector' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should be possible to add a simple variant to a simple selector', () => { - let selector = '.text-center' - let candidate = 'hover:text-center' +it('should be possible to add a simple variant to a simple selector', () => { + let selector = '.text-center' + let candidate = 'hover:text-center' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual('.hover\\:text-center:hover') +}) + +it('should be possible to add a multiple simple variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'focus:hover:text-center' + + let formats = [ + { format: '&:hover', isArbitraryVariant: false }, + { format: '&:focus', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.focus\\:hover\\:text-center:hover:focus' + ) +}) + +it('should be possible to add a simple variant to a selector containing escaped parts', () => { + let selector = '.bg-\\[rgba\\(0\\,0\\,0\\)\\]' + let candidate = 'hover:bg-[rgba(0,0,0)]' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' + ) +}) + +it('should be possible to add a simple variant to a selector containing escaped parts (escape is slightly different)', () => { + let selector = '.bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]' + let candidate = 'hover:bg-[rgba(0,0,0)]' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' + ) +}) + +it('should be possible to add a simple variant to a more complex selector', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'hover:space-x-4' + + let formats = [{ format: '&:hover', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add multiple simple variants to a more complex selector', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'disabled:focus:hover:space-x-4' + + let formats = [ + { format: '&:hover', isArbitraryVariant: false }, + { format: '&:focus', isArbitraryVariant: false }, + { format: '&:disabled', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.disabled\\:focus\\:hover\\:space-x-4:hover:focus:disabled > :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add a single merge variant to a simple selector', () => { + let selector = '.text-center' + let candidate = 'group-hover:text-center' + + let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover .group-hover\\:text-center' + ) +}) + +it('should be possible to add multiple merge variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'group-focus:group-hover:text-center' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.group):focus &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:focus:hover .group-focus\\:group-hover\\:text-center' + ) +}) + +it('should be possible to add a single merge variant to a more complex selector', () => { + let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' + let candidate = 'group-hover:space-x-4' + + let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover .group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add multiple merge variants to a more complex selector', () => { + let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' + let candidate = 'group-focus:group-hover:space-x-4' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.group):focus &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:focus:hover .group-focus\\:group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should be possible to add multiple unique merge variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'peer-focus:group-hover:text-center' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.peer):focus ~ &' }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.peer:focus ~ .group:hover .peer-focus\\:group-hover\\:text-center' + ) +}) + +it('should be possible to add multiple unique merge variants to a simple selector', () => { + let selector = '.text-center' + let candidate = 'group-hover:peer-focus:text-center' + + let formats = [ + { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover .peer:focus ~ .group-hover\\:peer-focus\\:text-center' + ) +}) + +it('should be possible to use multiple :merge() calls with different "arguments"', () => { + let selector = '.foo' + let candidate = 'peer-focus:group-focus:peer-hover:group-hover:foo' + + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, + { format: ':merge(.peer):hover ~ &', isArbitraryVariant: false }, + { format: ':merge(.group):focus &', isArbitraryVariant: false }, + { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.peer:focus:hover ~ .group:focus:hover .peer-focus\\:group-focus\\:peer-hover\\:group-hover\\:foo' + ) +}) + +it('group hover and prose headings combination', () => { + let selector = '.text-center' + let candidate = 'group-hover:prose-headings:text-center' + let formats = [ + { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings + { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover :where(.group-hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4)' + ) +}) + +it('group hover and prose headings combination flipped', () => { + let selector = '.text-center' + let candidate = 'prose-headings:group-hover:text-center' + let formats = [ + { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover + { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + ':where(.group:hover .prose-headings\\:group-hover\\:text-center) :is(h1, h2, h3, h4)' + ) +}) + +it('should be possible to handle a complex utility', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'peer-disabled:peer-first-child:group-hover:group-focus:focus:hover:space-x-4' + let formats = [ + { format: '&:hover', isArbitraryVariant: false }, // Hover + { format: '&:focus', isArbitraryVariant: false }, // Focus + { format: ':merge(.group):focus &', isArbitraryVariant: false }, // Group focus + { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group hover + { format: ':merge(.peer):first-child ~ &', isArbitraryVariant: false }, // Peer first-child + { format: ':merge(.peer):disabled ~ &', isArbitraryVariant: false }, // Peer disabled + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.peer:disabled:first-child ~ .group:hover:focus .peer-disabled\\:peer-first-child\\:group-hover\\:group-focus\\:focus\\:hover\\:space-x-4:hover:focus > :not([hidden]) ~ :not([hidden])' + ) +}) + +it('should match base utilities that are prefixed', () => { + let context = { tailwindConfig: { prefix: 'tw-' } } + let selector = '.tw-text-center' + let candidate = 'tw-text-center' + let formats = [] + + expect(finalizeSelector(selector, formats, { candidate, context })).toEqual('.tw-text-center') +}) + +it('should prefix classes from variants', () => { + let context = { tailwindConfig: { prefix: 'tw-' } } + let selector = '.tw-text-center' + let candidate = 'foo:tw-text-center' + let formats = [{ format: '.foo &', isArbitraryVariant: false }] + + expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( + '.tw-foo .foo\\:tw-text-center' + ) +}) + +it('should not prefix classes from arbitrary variants', () => { + let context = { tailwindConfig: { prefix: 'tw-' } } + let selector = '.tw-text-center' + let candidate = '[.foo_&]:tw-text-center' + let formats = [{ format: '.foo &', isArbitraryVariant: true }] + + expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( + '.foo .\\[\\.foo_\\&\\]\\:tw-text-center' + ) +}) + +it('Merged selectors with mixed combinators uses the first one', () => { + // This isn't explicitly specced behavior but it is how it works today + + let selector = '.text-center' + let candidate = 'text-center' + let formats = [ + { format: ':merge(.group):focus > &', isArbitraryVariant: true }, + { format: ':merge(.group):hover &', isArbitraryVariant: true }, + ] + + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.group:hover:focus > .text-center' + ) +}) + +describe('real examples', () => { + it('example a', () => { + let selector = '.placeholder-red-500::placeholder' + let candidate = 'hover:placeholder-red-500' let formats = [{ format: '&:hover', isArbitraryVariant: false }] - expect(finalizeSelector(selector, formats, { candidate })).toEqual('.hover\\:text-center:hover') + expect(finalizeSelector(selector, formats, { candidate })).toEqual( + '.hover\\:placeholder-red-500:hover::placeholder' + ) }) - it('should be possible to add a multiple simple variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'focus:hover:text-center' + it('example b', () => { + let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' + let candidate = 'group-hover:hover:space-x-4' let formats = [ { format: '&:hover', isArbitraryVariant: false }, - { format: '&:focus', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.focus\\:hover\\:text-center:hover:focus' - ) - }) - - it('should be possible to add a simple variant to a selector containing escaped parts', () => { - let selector = '.bg-\\[rgba\\(0\\,0\\,0\\)\\]' - let candidate = 'hover:bg-[rgba(0,0,0)]' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' - ) - }) - - it('should be possible to add a simple variant to a selector containing escaped parts (escape is slightly different)', () => { - let selector = '.bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]' - let candidate = 'hover:bg-[rgba(0,0,0)]' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:bg-\\[rgba\\(0\\2c 0\\2c 0\\)\\]:hover' - ) - }) - - it('should be possible to add a simple variant to a more complex selector', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'hover:space-x-4' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add multiple simple variants to a more complex selector', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'disabled:focus:hover:space-x-4' - - let formats = [ - { format: '&:hover', isArbitraryVariant: false }, - { format: '&:focus', isArbitraryVariant: false }, - { format: '&:disabled', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.disabled\\:focus\\:hover\\:space-x-4:hover:focus:disabled > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add a single merge variant to a simple selector', () => { - let selector = '.text-center' - let candidate = 'group-hover:text-center' - - let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .group-hover\\:text-center' - ) - }) - - it('should be possible to add multiple merge variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'group-focus:group-hover:text-center' - - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.group):focus &', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:focus:hover .group-focus\\:group-hover\\:text-center' - ) - }) - - it('should be possible to add a single merge variant to a more complex selector', () => { - let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' - let candidate = 'group-hover:space-x-4' - - let formats = [{ format: ':merge(.group):hover &', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add multiple merge variants to a more complex selector', () => { - let selector = '.space-x-4 ~ :not([hidden]) ~ :not([hidden])' - let candidate = 'group-focus:group-hover:space-x-4' - - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.group):focus &', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:focus:hover .group-focus\\:group-hover\\:space-x-4 ~ :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should be possible to add multiple unique merge variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'peer-focus:group-hover:text-center' - - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.peer):focus ~ &' }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.peer:focus ~ .group:hover .peer-focus\\:group-hover\\:text-center' - ) - }) - - it('should be possible to add multiple unique merge variants to a simple selector', () => { - let selector = '.text-center' - let candidate = 'group-hover:peer-focus:text-center' - - let formats = [ - { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, { format: ':merge(.group):hover &', isArbitraryVariant: false }, ] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .peer:focus ~ .group-hover\\:peer-focus\\:text-center' + '.group:hover .group-hover\\:hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' ) }) - it('should be possible to use multiple :merge() calls with different "arguments"', () => { - let selector = '.foo' - let candidate = 'peer-focus:group-focus:peer-hover:group-hover:foo' + it('should work for group-hover and class dark mode combinations', () => { + let selector = '.text-center' + let candidate = 'dark:group-hover:text-center' let formats = [ { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: ':merge(.peer):hover ~ &', isArbitraryVariant: false }, - { format: ':merge(.group):focus &', isArbitraryVariant: false }, - { format: ':merge(.peer):focus ~ &', isArbitraryVariant: false }, + { format: '.dark &', isArbitraryVariant: false }, ] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.peer:focus:hover ~ .group:focus:hover .peer-focus\\:group-focus\\:peer-hover\\:group-hover\\:foo' + '.dark .group:hover .dark\\:group-hover\\:text-center' ) }) - it('group hover and prose headings combination', () => { + it('should work for group-hover and class dark mode combinations (reversed)', () => { let selector = '.text-center' - let candidate = 'group-hover:prose-headings:text-center' + let candidate = 'group-hover:dark:text-center' + let formats = [ - { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings - { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover + { format: '.dark &' }, + { format: ':merge(.group):hover &', isArbitraryVariant: false }, ] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover :where(.group-hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4)' + '.group:hover .dark .group-hover\\:dark\\:text-center' ) }) - it('group hover and prose headings combination flipped', () => { - let selector = '.text-center' - let candidate = 'prose-headings:group-hover:text-center' - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group Hover - { format: ':where(&) :is(h1, h2, h3, h4)', isArbitraryVariant: false }, // Prose Headings - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - ':where(.group:hover .prose-headings\\:group-hover\\:text-center) :is(h1, h2, h3, h4)' - ) - }) - - it('should be possible to handle a complex utility', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'peer-disabled:peer-first-child:group-hover:group-focus:focus:hover:space-x-4' - let formats = [ - { format: '&:hover', isArbitraryVariant: false }, // Hover - { format: '&:focus', isArbitraryVariant: false }, // Focus - { format: ':merge(.group):focus &', isArbitraryVariant: false }, // Group focus - { format: ':merge(.group):hover &', isArbitraryVariant: false }, // Group hover - { format: ':merge(.peer):first-child ~ &', isArbitraryVariant: false }, // Peer first-child - { format: ':merge(.peer):disabled ~ &', isArbitraryVariant: false }, // Peer disabled - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.peer:disabled:first-child ~ .group:hover:focus .peer-disabled\\:peer-first-child\\:group-hover\\:group-focus\\:focus\\:hover\\:space-x-4:hover:focus > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should match base utilities that are prefixed', () => { - let context = { tailwindConfig: { prefix: 'tw-' } } - let selector = '.tw-text-center' - let candidate = 'tw-text-center' - let formats = [] - - expect(finalizeSelector(selector, formats, { candidate, context })).toEqual('.tw-text-center') - }) - - it('should prefix classes from variants', () => { - let context = { tailwindConfig: { prefix: 'tw-' } } - let selector = '.tw-text-center' - let candidate = 'foo:tw-text-center' - let formats = [{ format: '.foo &', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( - '.tw-foo .foo\\:tw-text-center' - ) - }) - - it('should not prefix classes from arbitrary variants', () => { - let context = { tailwindConfig: { prefix: 'tw-' } } - let selector = '.tw-text-center' - let candidate = '[.foo_&]:tw-text-center' - let formats = [{ format: '.foo &', isArbitraryVariant: true }] - - expect(finalizeSelector(selector, formats, { candidate, context })).toEqual( - '.foo .\\[\\.foo_\\&\\]\\:tw-text-center' - ) - }) - - it('Merged selectors with mixed combinators uses the first one', () => { - // This isn't explicitly specced behavior but it is how it works today - - let selector = '.text-center' - let candidate = 'text-center' - let formats = [ - { format: ':merge(.group):focus > &', isArbitraryVariant: true }, - { format: ':merge(.group):hover &', isArbitraryVariant: true }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover:focus > .text-center' - ) - }) - - describe('real examples', () => { - it('example a', () => { - let selector = '.placeholder-red-500::placeholder' - let candidate = 'hover:placeholder-red-500' - - let formats = [{ format: '&:hover', isArbitraryVariant: false }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.hover\\:placeholder-red-500:hover::placeholder' - ) - }) - - it('example b', () => { - let selector = '.space-x-4 > :not([hidden]) ~ :not([hidden])' - let candidate = 'group-hover:hover:space-x-4' - - let formats = [ - { format: '&:hover', isArbitraryVariant: false }, - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - ] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .group-hover\\:hover\\:space-x-4:hover > :not([hidden]) ~ :not([hidden])' - ) - }) - - it('should work for group-hover and class dark mode combinations', () => { + describe('prose-headings', () => { + it('should be possible to use hover:prose-headings:text-center', () => { let selector = '.text-center' - let candidate = 'dark:group-hover:text-center' + let candidate = 'hover:prose-headings:text-center' - let formats = [ - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - { format: '.dark &', isArbitraryVariant: false }, - ] + let formats = [{ format: ':where(&) :is(h1, h2, h3, h4)' }, { format: '&:hover' }] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.dark .group:hover .dark\\:group-hover\\:text-center' + ':where(.hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4):hover' ) }) - it('should work for group-hover and class dark mode combinations (reversed)', () => { + it('should be possible to use prose-headings:hover:text-center', () => { let selector = '.text-center' - let candidate = 'group-hover:dark:text-center' + let candidate = 'prose-headings:hover:text-center' - let formats = [ - { format: '.dark &' }, - { format: ':merge(.group):hover &', isArbitraryVariant: false }, - ] + let formats = [{ format: '&:hover' }, { format: ':where(&) :is(h1, h2, h3, h4)' }] expect(finalizeSelector(selector, formats, { candidate })).toEqual( - '.group:hover .dark .group-hover\\:dark\\:text-center' + ':where(.prose-headings\\:hover\\:text-center:hover) :is(h1, h2, h3, h4)' ) }) - - describe('prose-headings', () => { - it('should be possible to use hover:prose-headings:text-center', () => { - let selector = '.text-center' - let candidate = 'hover:prose-headings:text-center' - - let formats = [{ format: ':where(&) :is(h1, h2, h3, h4)' }, { format: '&:hover' }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - ':where(.hover\\:prose-headings\\:text-center) :is(h1, h2, h3, h4):hover' - ) - }) - - it('should be possible to use prose-headings:hover:text-center', () => { - let selector = '.text-center' - let candidate = 'prose-headings:hover:text-center' - - let formats = [{ format: '&:hover' }, { format: ':where(&) :is(h1, h2, h3, h4)' }] - - expect(finalizeSelector(selector, formats, { candidate })).toEqual( - ':where(.prose-headings\\:hover\\:text-center:hover) :is(h1, h2, h3, h4)' - ) - }) - }) - }) - - describe('pseudo elements', () => { - it.each` - before | after - ${'&::before'} | ${'&::before'} - ${'&::before:hover'} | ${'&:hover::before'} - ${'&:before:hover'} | ${'&:hover:before'} - ${'&::file-selector-button:hover'} | ${'&::file-selector-button:hover'} - ${'&:hover::file-selector-button'} | ${'&:hover::file-selector-button'} - ${'.parent:hover &'} | ${'.parent:hover &'} - ${'.parent::before &'} | ${'.parent &::before'} - ${'.parent::before &:hover'} | ${'.parent &:hover::before'} - ${':where(&::before) :is(h1, h2, h3, h4)'} | ${':where(&) :is(h1, h2, h3, h4)::before'} - ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} | ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} - ${'#app :is(.dark &::before)'} | ${'#app :is(.dark &)::before'} - ${'#app :is(:is(.dark &)::before)'} | ${'#app :is(:is(.dark &))::before'} - ${'#app :is(.foo::file-selector-button)'} | ${'#app :is(.foo)::file-selector-button'} - ${'#app :is(.foo::-webkit-progress-bar)'} | ${'#app :is(.foo)::-webkit-progress-bar'} - ${'.parent::marker li'} | ${'.parent li::marker'} - ${'.parent::selection li'} | ${'.parent li::selection'} - ${'.parent::placeholder input'} | ${'.parent input::placeholder'} - ${'.parent::backdrop dialog'} | ${'.parent dialog::backdrop'} - `('should translate "$before" into "$after"', ({ before, after }) => { - let result = finalizeSelector('.a', [{ format: before, isArbitraryVariant: false }], { - candidate: 'a', - }) - - expect(result).toEqual(after.replace('&', '.a')) - }) + }) +}) + +describe('pseudo elements', () => { + it.each` + before | after + ${'&::before'} | ${'&::before'} + ${'&::before:hover'} | ${'&:hover::before'} + ${'&:before:hover'} | ${'&:hover:before'} + ${'&::file-selector-button:hover'} | ${'&::file-selector-button:hover'} + ${'&:hover::file-selector-button'} | ${'&:hover::file-selector-button'} + ${'.parent:hover &'} | ${'.parent:hover &'} + ${'.parent::before &'} | ${'.parent &::before'} + ${'.parent::before &:hover'} | ${'.parent &:hover::before'} + ${':where(&::before) :is(h1, h2, h3, h4)'} | ${':where(&) :is(h1, h2, h3, h4)::before'} + ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} | ${':where(&::file-selector-button) :is(h1, h2, h3, h4)'} + ${'#app :is(.dark &::before)'} | ${'#app :is(.dark &)::before'} + ${'#app :is(:is(.dark &)::before)'} | ${'#app :is(:is(.dark &))::before'} + ${'#app :is(.foo::file-selector-button)'} | ${'#app :is(.foo)::file-selector-button'} + ${'#app :is(.foo::-webkit-progress-bar)'} | ${'#app :is(.foo)::-webkit-progress-bar'} + ${'.parent::marker li'} | ${'.parent li::marker'} + ${'.parent::selection li'} | ${'.parent li::selection'} + ${'.parent::placeholder input'} | ${'.parent input::placeholder'} + ${'.parent::backdrop dialog'} | ${'.parent dialog::backdrop'} + `('should translate "$before" into "$after"', ({ before, after }) => { + let result = finalizeSelector('.a', [{ format: before, isArbitraryVariant: false }], { + candidate: 'a', + }) + + expect(result).toEqual(after.replace('&', '.a')) }) }) diff --git a/tests/generate-rules.test.js b/tests/generate-rules.test.js index 3aa8592bc..57740c128 100644 --- a/tests/generate-rules.test.js +++ b/tests/generate-rules.test.js @@ -1,48 +1,46 @@ import { generateRules } from '../src/lib/generateRules' import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck, css } from './util/run' +import { css } from './util/run' -crosscheck(() => { - it('should not generate rules that are incorrect', () => { - let config = { - plugins: [ - ({ matchVariant }) => { - matchVariant('@', (value) => `@container (min-width: ${value})`) - }, - ], +it('should not generate rules that are incorrect', () => { + let config = { + plugins: [ + ({ matchVariant }) => { + matchVariant('@', (value) => `@container (min-width: ${value})`) + }, + ], + } + let context = createContext(resolveConfig(config)) + let rules = generateRules( + new Set([ + // Invalid, missing `-` + 'group[:hover]:underline', + + // Invalid, `-` should not be there + '@-[200px]:underline', + + // Valid + 'group-[:hover]:underline', + '@[200px]:underline', + ]), + context + ) + + // Ensure we only have 2 valid rules + expect(rules).toHaveLength(2) + + // Ensure we have the correct values + expect(rules[0][1].toString()).toMatchFormattedCss(css` + .group:hover .group-\[\:hover\]\:underline { + text-decoration-line: underline; } - let context = createContext(resolveConfig(config)) - let rules = generateRules( - new Set([ - // Invalid, missing `-` - 'group[:hover]:underline', - - // Invalid, `-` should not be there - '@-[200px]:underline', - - // Valid - 'group-[:hover]:underline', - '@[200px]:underline', - ]), - context - ) - - // Ensure we only have 2 valid rules - expect(rules).toHaveLength(2) - - // Ensure we have the correct values - expect(rules[0][1].toString()).toMatchFormattedCss(css` - .group:hover .group-\[\:hover\]\:underline { + `) + expect(rules[1][1].toString()).toMatchFormattedCss(css` + @container (min-width: 200px) { + .\@\[200px\]\:underline { text-decoration-line: underline; } - `) - expect(rules[1][1].toString()).toMatchFormattedCss(css` - @container (min-width: 200px) { - .\@\[200px\]\:underline { - text-decoration-line: underline; - } - } - `) - }) + } + `) }) diff --git a/tests/getClassList.test.js b/tests/getClassList.test.js index 671a767ec..63dfea88c 100644 --- a/tests/getClassList.test.js +++ b/tests/getClassList.test.js @@ -1,228 +1,225 @@ import resolveConfig from '../src/public/resolve-config' import plugin from '../src/public/create-plugin' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should generate every possible class, without variants', () => { - let config = {} +it('should generate every possible class, without variants', () => { + let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() - expect(classes).toBeInstanceOf(Array) + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() + expect(classes).toBeInstanceOf(Array) - // Verify we have a `container` for the 'components' section. - expect(classes).toContain('container') + // Verify we have a `container` for the 'components' section. + expect(classes).toContain('container') - // Verify we handle the DEFAULT case correctly - expect(classes).toContain('border') + // Verify we handle the DEFAULT case correctly + expect(classes).toContain('border') - // Verify we handle negative values correctly - expect(classes).toContain('-inset-1/4') - expect(classes).toContain('-m-0') - expect(classes).not.toContain('-uppercase') - expect(classes).not.toContain('-opacity-50') + // Verify we handle negative values correctly + expect(classes).toContain('-inset-1/4') + expect(classes).toContain('-m-0') + expect(classes).not.toContain('-uppercase') + expect(classes).not.toContain('-opacity-50') - config = { theme: { extend: { margin: { DEFAULT: '5px' } } } } - context = createContext(resolveConfig(config)) - classes = context.getClassList() + config = { theme: { extend: { margin: { DEFAULT: '5px' } } } } + context = createContext(resolveConfig(config)) + classes = context.getClassList() - expect(classes).not.toContain('-m-DEFAULT') - }) + expect(classes).not.toContain('-m-DEFAULT') +}) - it('should generate every possible class while handling negatives and prefixes', () => { - let config = { prefix: 'tw-' } - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() - expect(classes).toBeInstanceOf(Array) +it('should generate every possible class while handling negatives and prefixes', () => { + let config = { prefix: 'tw-' } + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() + expect(classes).toBeInstanceOf(Array) - // Verify we have a `container` for the 'components' section. - expect(classes).toContain('tw-container') + // Verify we have a `container` for the 'components' section. + expect(classes).toContain('tw-container') - // Verify we handle the DEFAULT case correctly - expect(classes).toContain('tw-border') + // Verify we handle the DEFAULT case correctly + expect(classes).toContain('tw-border') - // Verify we handle negative values correctly - expect(classes).toContain('-tw-inset-1/4') - expect(classes).toContain('-tw-m-0') - expect(classes).not.toContain('-tw-uppercase') - expect(classes).not.toContain('-tw-opacity-50') + // Verify we handle negative values correctly + expect(classes).toContain('-tw-inset-1/4') + expect(classes).toContain('-tw-m-0') + expect(classes).not.toContain('-tw-uppercase') + expect(classes).not.toContain('-tw-opacity-50') - // These utilities do work but there's no reason to generate - // them alongside the `-{prefix}-{utility}` versions - expect(classes).not.toContain('tw--inset-1/4') - expect(classes).not.toContain('tw--m-0') + // These utilities do work but there's no reason to generate + // them alongside the `-{prefix}-{utility}` versions + expect(classes).not.toContain('tw--inset-1/4') + expect(classes).not.toContain('tw--m-0') - config = { - prefix: 'tw-', - theme: { extend: { margin: { DEFAULT: '5px' } } }, - } - context = createContext(resolveConfig(config)) - classes = context.getClassList() + config = { + prefix: 'tw-', + theme: { extend: { margin: { DEFAULT: '5px' } } }, + } + context = createContext(resolveConfig(config)) + classes = context.getClassList() - expect(classes).not.toContain('-tw-m-DEFAULT') - }) + expect(classes).not.toContain('-tw-m-DEFAULT') +}) - it('should not generate utilities with opacity by default', () => { - let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() +it('should not generate utilities with opacity by default', () => { + let config = {} + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() - expect(classes).not.toContain('bg-red-500/50') - }) + expect(classes).not.toContain('bg-red-500/50') +}) - it('should not include metadata by default', () => { - let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() +it('should not include metadata by default', () => { + let config = {} + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() - expect(classes.every((cls) => typeof cls === 'string')).toEqual(true) + expect(classes.every((cls) => typeof cls === 'string')).toEqual(true) - expect(classes).toContain('bg-red-500') - expect(classes).toContain('text-2xl') - }) + expect(classes).toContain('bg-red-500') + expect(classes).toContain('text-2xl') +}) - it('should generate utilities with modifier data when requested', () => { - let config = {} - let context = createContext(resolveConfig(config)) - let classes = context.getClassList({ includeMetadata: true }) +it('should generate utilities with modifier data when requested', () => { + let config = {} + let context = createContext(resolveConfig(config)) + let classes = context.getClassList({ includeMetadata: true }) - expect(classes).not.toContain('bg-red-500') - expect(classes).not.toContain('text-2xl') + expect(classes).not.toContain('bg-red-500') + expect(classes).not.toContain('text-2xl') - expect(classes).toContainEqual([ - 'bg-red-500', - { - modifiers: [ - '0', - '5', - '10', - '20', - '25', - '30', - '40', - '50', - '60', - '70', - '75', - '80', - '90', - '95', - '100', - ], - }, - ]) - expect(classes).toContainEqual([ - 'text-2xl', - { - modifiers: [ - '3', - '4', - '5', - '6', - '7', - '8', - '9', - '10', - 'none', - 'tight', - 'snug', - 'normal', - 'relaxed', - 'loose', - ], - }, - ]) - }) - - it('should generate plugin-defined utilities with modifier data when requested', () => { - let config = { - plugins: [ - plugin(function ({ matchUtilities }) { - matchUtilities( - { - foo: (value) => { - return { margin: value } - }, - }, - { - values: { xl: '32px' }, - modifiers: { bar: 'something' }, - } - ) - matchUtilities( - { - 'foo-negative': (value) => { - return { margin: value } - }, - }, - { - values: { xl: '32px' }, - modifiers: { bar: 'something' }, - supportsNegativeValues: true, - } - ) - }), + expect(classes).toContainEqual([ + 'bg-red-500', + { + modifiers: [ + '0', + '5', + '10', + '20', + '25', + '30', + '40', + '50', + '60', + '70', + '75', + '80', + '90', + '95', + '100', ], - } - let context = createContext(resolveConfig(config)) - let classes = context.getClassList({ includeMetadata: true }) - - expect(classes).toContainEqual(['foo-xl', { modifiers: ['bar'] }]) - expect(classes).toContainEqual(['foo-negative-xl', { modifiers: ['bar'] }]) - expect(classes).toContainEqual(['-foo-negative-xl', { modifiers: ['bar'] }]) - expect(classes).not.toContain('foo-xl') - expect(classes).not.toContain('-foo-xl') - expect(classes).not.toContainEqual(['-foo-xl', { modifiers: ['bar'] }]) - }) - - it('should not generate utilities with opacity even if safe-listed', () => { - let config = { - safelist: [ - { - pattern: /^bg-red-(400|500)(\/(40|50))?$/, - }, + }, + ]) + expect(classes).toContainEqual([ + 'text-2xl', + { + modifiers: [ + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '10', + 'none', + 'tight', + 'snug', + 'normal', + 'relaxed', + 'loose', ], - } + }, + ]) +}) - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() - - expect(classes).not.toContain('bg-red-500/50') - }) - - it('should not generate utilities that are set to undefined or null to so that they are removed', () => { - let config = { - theme: { - extend: { - colors: { - red: null, - green: undefined, - blue: { - 100: null, - 200: undefined, +it('should generate plugin-defined utilities with modifier data when requested', () => { + let config = { + plugins: [ + plugin(function ({ matchUtilities }) { + matchUtilities( + { + foo: (value) => { + return { margin: value } }, }, + { + values: { xl: '32px' }, + modifiers: { bar: 'something' }, + } + ) + matchUtilities( + { + 'foo-negative': (value) => { + return { margin: value } + }, + }, + { + values: { xl: '32px' }, + modifiers: { bar: 'something' }, + supportsNegativeValues: true, + } + ) + }), + ], + } + let context = createContext(resolveConfig(config)) + let classes = context.getClassList({ includeMetadata: true }) + + expect(classes).toContainEqual(['foo-xl', { modifiers: ['bar'] }]) + expect(classes).toContainEqual(['foo-negative-xl', { modifiers: ['bar'] }]) + expect(classes).toContainEqual(['-foo-negative-xl', { modifiers: ['bar'] }]) + expect(classes).not.toContain('foo-xl') + expect(classes).not.toContain('-foo-xl') + expect(classes).not.toContainEqual(['-foo-xl', { modifiers: ['bar'] }]) +}) + +it('should not generate utilities with opacity even if safe-listed', () => { + let config = { + safelist: [ + { + pattern: /^bg-red-(400|500)(\/(40|50))?$/, + }, + ], + } + + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() + + expect(classes).not.toContain('bg-red-500/50') +}) + +it('should not generate utilities that are set to undefined or null to so that they are removed', () => { + let config = { + theme: { + extend: { + colors: { + red: null, + green: undefined, + blue: { + 100: null, + 200: undefined, + }, }, }, - safelist: [ - { - pattern: /^bg-(red|green|blue)-.*$/, - }, - ], - } + }, + safelist: [ + { + pattern: /^bg-(red|green|blue)-.*$/, + }, + ], + } - let context = createContext(resolveConfig(config)) - let classes = context.getClassList() + let context = createContext(resolveConfig(config)) + let classes = context.getClassList() - expect(classes).not.toContain('bg-red-100') // Red is `null` + expect(classes).not.toContain('bg-red-100') // Red is `null` - expect(classes).not.toContain('bg-green-100') // Green is `undefined` + expect(classes).not.toContain('bg-green-100') // Green is `undefined` - expect(classes).not.toContain('bg-blue-100') // Blue.100 is `null` - expect(classes).not.toContain('bg-blue-200') // Blue.200 is `undefined` + expect(classes).not.toContain('bg-blue-100') // Blue.100 is `null` + expect(classes).not.toContain('bg-blue-200') // Blue.200 is `undefined` - expect(classes).toContain('bg-blue-50') - expect(classes).toContain('bg-blue-300') - }) + expect(classes).toContain('bg-blue-50') + expect(classes).toContain('bg-blue-300') }) diff --git a/tests/getSortOrder.test.js b/tests/getSortOrder.test.js index 4526c4874..0863d268d 100644 --- a/tests/getSortOrder.test.js +++ b/tests/getSortOrder.test.js @@ -1,7 +1,6 @@ import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' import bigSign from '../src/util/bigSign' -import { crosscheck } from './util/run' /** * This is a function that the prettier-plugin-tailwindcss would use. It would @@ -25,121 +24,119 @@ function defaultSort(arrayOfTuples) { .join(' ') } -crosscheck(() => { - it('should return a list of tuples with the sort order', () => { - let input = 'font-bold underline hover:font-medium unknown' - let config = {} - let context = createContext(resolveConfig(config)) - expect(context.getClassOrder(input.split(' '))).toEqual([ - ['font-bold', expect.any(BigInt)], - ['underline', expect.any(BigInt)], - ['hover:font-medium', expect.any(BigInt)], +it('should return a list of tuples with the sort order', () => { + let input = 'font-bold underline hover:font-medium unknown' + let config = {} + let context = createContext(resolveConfig(config)) + expect(context.getClassOrder(input.split(' '))).toEqual([ + ['font-bold', expect.any(BigInt)], + ['underline', expect.any(BigInt)], + ['hover:font-medium', expect.any(BigInt)], - // Unknown values receive `null` - ['unknown', null], - ]) - }) + // Unknown values receive `null` + ['unknown', null], + ]) +}) - it.each([ - // Utitlies - ['px-3 p-1 py-3', 'p-1 px-3 py-3'], +it.each([ + // Utitlies + ['px-3 p-1 py-3', 'p-1 px-3 py-3'], - // Utitlies and components - ['px-4 container', 'container px-4'], + // Utitlies and components + ['px-4 container', 'container px-4'], - // Utilities with variants - ['px-3 focus:hover:p-3 hover:p-1 py-3', 'px-3 py-3 hover:p-1 focus:hover:p-3'], + // Utilities with variants + ['px-3 focus:hover:p-3 hover:p-1 py-3', 'px-3 py-3 hover:p-1 focus:hover:p-3'], - // Utitlies with important - ['px-3 !py-4', '!py-4 px-3'], - ['!py-4 px-3', '!py-4 px-3'], + // Utitlies with important + ['px-3 !py-4', '!py-4 px-3'], + ['!py-4 px-3', '!py-4 px-3'], - // Components with variants - ['hover:container container', 'container hover:container'], + // Components with variants + ['hover:container container', 'container hover:container'], - // Components and utilities with variants - [ - 'focus:hover:container hover:underline hover:container p-1', - 'p-1 hover:container focus:hover:container hover:underline', - ], + // Components and utilities with variants + [ + 'focus:hover:container hover:underline hover:container p-1', + 'p-1 hover:container focus:hover:container hover:underline', + ], - // Leave user css order alone, and move to the front - ['b p-1 a', 'b a p-1'], - ['hover:b focus:p-1 a', 'hover:b a focus:p-1'], + // Leave user css order alone, and move to the front + ['b p-1 a', 'b a p-1'], + ['hover:b focus:p-1 a', 'hover:b a focus:p-1'], - // Add special treatment for `group` and `peer` - ['a peer container underline', 'a peer container underline'], - ])('should sort "%s" based on the order we generate them in to "%s"', (input, output) => { - let config = {} + // Add special treatment for `group` and `peer` + ['a peer container underline', 'a peer container underline'], +])('should sort "%s" based on the order we generate them in to "%s"', (input, output) => { + let config = {} + let context = createContext(resolveConfig(config)) + expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) +}) + +it.each([ + // Utitlies + ['tw-px-3 tw-p-1 tw-py-3', 'tw-p-1 tw-px-3 tw-py-3'], + + // Utitlies and components + ['tw-px-4 tw-container', 'tw-container tw-px-4'], + + // Utilities with variants + [ + 'tw-px-3 focus:hover:tw-p-3 hover:tw-p-1 tw-py-3', + 'tw-px-3 tw-py-3 hover:tw-p-1 focus:hover:tw-p-3', + ], + + // Utitlies with important + ['tw-px-3 !tw-py-4', '!tw-py-4 tw-px-3'], + ['!tw-py-4 tw-px-3', '!tw-py-4 tw-px-3'], + + // Components with variants + ['hover:tw-container tw-container', 'tw-container hover:tw-container'], + + // Components and utilities with variants + [ + 'focus:hover:tw-container hover:tw-underline hover:tw-container tw-p-1', + 'tw-p-1 hover:tw-container focus:hover:tw-container hover:tw-underline', + ], + + // Leave user css order alone, and move to the front + ['b tw-p-1 a', 'b a tw-p-1'], + ['hover:b focus:tw-p-1 a', 'hover:b a focus:tw-p-1'], + + // Add special treatment for `group` and `peer` + ['a tw-peer tw-container tw-underline', 'a tw-peer tw-container tw-underline'], +])( + 'should sort "%s" with prefixex based on the order we generate them in to "%s"', + (input, output) => { + let config = { prefix: 'tw-' } let context = createContext(resolveConfig(config)) expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - }) + } +) - it.each([ - // Utitlies - ['tw-px-3 tw-p-1 tw-py-3', 'tw-p-1 tw-px-3 tw-py-3'], - - // Utitlies and components - ['tw-px-4 tw-container', 'tw-container tw-px-4'], - - // Utilities with variants +it('sorts classes deterministically across multiple class lists', () => { + let classes = [ [ - 'tw-px-3 focus:hover:tw-p-3 hover:tw-p-1 tw-py-3', - 'tw-px-3 tw-py-3 hover:tw-p-1 focus:hover:tw-p-3', + 'a-class px-3 p-1 b-class py-3 bg-red-500 bg-blue-500', + 'a-class b-class bg-blue-500 bg-red-500 p-1 px-3 py-3', ], - - // Utitlies with important - ['tw-px-3 !tw-py-4', '!tw-py-4 tw-px-3'], - ['!tw-py-4 tw-px-3', '!tw-py-4 tw-px-3'], - - // Components with variants - ['hover:tw-container tw-container', 'tw-container hover:tw-container'], - - // Components and utilities with variants [ - 'focus:hover:tw-container hover:tw-underline hover:tw-container tw-p-1', - 'tw-p-1 hover:tw-container focus:hover:tw-container hover:tw-underline', + 'px-3 b-class p-1 py-3 bg-blue-500 a-class bg-red-500', + 'b-class a-class bg-blue-500 bg-red-500 p-1 px-3 py-3', ], + ] - // Leave user css order alone, and move to the front - ['b tw-p-1 a', 'b a tw-p-1'], - ['hover:b focus:tw-p-1 a', 'hover:b a focus:tw-p-1'], + let config = {} - // Add special treatment for `group` and `peer` - ['a tw-peer tw-container tw-underline', 'a tw-peer tw-container tw-underline'], - ])( - 'should sort "%s" with prefixex based on the order we generate them in to "%s"', - (input, output) => { - let config = { prefix: 'tw-' } - let context = createContext(resolveConfig(config)) - expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - } - ) + // Same context, different class lists + let context = createContext(resolveConfig(config)) + for (const [input, output] of classes) { + expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) + } - it('sorts classes deterministically across multiple class lists', () => { - let classes = [ - [ - 'a-class px-3 p-1 b-class py-3 bg-red-500 bg-blue-500', - 'a-class b-class bg-blue-500 bg-red-500 p-1 px-3 py-3', - ], - [ - 'px-3 b-class p-1 py-3 bg-blue-500 a-class bg-red-500', - 'b-class a-class bg-blue-500 bg-red-500 p-1 px-3 py-3', - ], - ] - - let config = {} - - // Same context, different class lists - let context = createContext(resolveConfig(config)) - for (const [input, output] of classes) { - expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - } - - // Different context, different class lists - for (const [input, output] of classes) { - context = createContext(resolveConfig(config)) - expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) - } - }) + // Different context, different class lists + for (const [input, output] of classes) { + context = createContext(resolveConfig(config)) + expect(defaultSort(context.getClassOrder(input.split(' ')))).toEqual(output) + } }) diff --git a/tests/getVariants.test.js b/tests/getVariants.test.js index 8d79f8243..af34fd0e3 100644 --- a/tests/getVariants.test.js +++ b/tests/getVariants.test.js @@ -2,188 +2,185 @@ import postcss from 'postcss' import selectorParser from 'postcss-selector-parser' import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should return a list of variants with meta information about the variant', () => { - let config = {} - let context = createContext(resolveConfig(config)) +it('should return a list of variants with meta information about the variant', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variants = context.getVariants() + let variants = context.getVariants() - expect(variants).toContainEqual({ - name: 'hover', - isArbitrary: false, - hasDash: true, - values: [], - selectors: expect.any(Function), - }) - - expect(variants).toContainEqual({ - name: 'group', - isArbitrary: true, - hasDash: true, - values: expect.any(Array), - selectors: expect.any(Function), - }) - - // `group-hover` now belongs to the `group` variant. The information exposed for the `group` - // variant is all you need. - expect(variants.find((v) => v.name === 'group-hover')).toBeUndefined() + expect(variants).toContainEqual({ + name: 'hover', + isArbitrary: false, + hasDash: true, + values: [], + selectors: expect.any(Function), }) - it('should provide selectors for simple variants', () => { - let config = {} - let context = createContext(resolveConfig(config)) - - let variants = context.getVariants() - - let variant = variants.find((v) => v.name === 'hover') - expect(variant.selectors()).toEqual(['&:hover']) + expect(variants).toContainEqual({ + name: 'group', + isArbitrary: true, + hasDash: true, + values: expect.any(Array), + selectors: expect.any(Function), }) - it('should provide selectors for parallel variants', () => { - let config = {} - let context = createContext(resolveConfig(config)) + // `group-hover` now belongs to the `group` variant. The information exposed for the `group` + // variant is all you need. + expect(variants.find((v) => v.name === 'group-hover')).toBeUndefined() +}) - let variants = context.getVariants() +it('should provide selectors for simple variants', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variant = variants.find((v) => v.name === 'marker') - expect(variant.selectors()).toEqual(['& *::marker', '&::marker']) - }) + let variants = context.getVariants() - it('should provide selectors for complex matchVariant variants like `group`', () => { - let config = {} - let context = createContext(resolveConfig(config)) + let variant = variants.find((v) => v.name === 'hover') + expect(variant.selectors()).toEqual(['&:hover']) +}) - let variants = context.getVariants() +it('should provide selectors for parallel variants', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variant = variants.find((v) => v.name === 'group') - expect(variant.selectors()).toEqual(['.group &']) - expect(variant.selectors({})).toEqual(['.group &']) - expect(variant.selectors({ value: 'hover' })).toEqual(['.group:hover &']) - expect(variant.selectors({ value: '.foo_&' })).toEqual(['.foo .group &']) - expect(variant.selectors({ modifier: 'foo', value: 'hover' })).toEqual(['.group\\/foo:hover &']) - expect(variant.selectors({ modifier: 'foo', value: '.foo_&' })).toEqual(['.foo .group\\/foo &']) - }) + let variants = context.getVariants() - it('should provide selectors for variants with atrules', () => { - let config = {} - let context = createContext(resolveConfig(config)) + let variant = variants.find((v) => v.name === 'marker') + expect(variant.selectors()).toEqual(['& *::marker', '&::marker']) +}) - let variants = context.getVariants() +it('should provide selectors for complex matchVariant variants like `group`', () => { + let config = {} + let context = createContext(resolveConfig(config)) - let variant = variants.find((v) => v.name === 'supports') - expect(variant.selectors({ value: 'display:grid' })).toEqual(['@supports (display:grid)']) - expect(variant.selectors({ value: 'aspect-ratio' })).toEqual([ - '@supports (aspect-ratio: var(--tw))', - ]) - }) + let variants = context.getVariants() - it('should provide selectors for custom plugins that do a combination of parallel variants with modifiers with arbitrary values and with atrules', () => { - let config = { - plugins: [ - function ({ matchVariant }) { - matchVariant('foo', (value, { modifier }) => { - return [ - ` + let variant = variants.find((v) => v.name === 'group') + expect(variant.selectors()).toEqual(['.group &']) + expect(variant.selectors({})).toEqual(['.group &']) + expect(variant.selectors({ value: 'hover' })).toEqual(['.group:hover &']) + expect(variant.selectors({ value: '.foo_&' })).toEqual(['.foo .group &']) + expect(variant.selectors({ modifier: 'foo', value: 'hover' })).toEqual(['.group\\/foo:hover &']) + expect(variant.selectors({ modifier: 'foo', value: '.foo_&' })).toEqual(['.foo .group\\/foo &']) +}) + +it('should provide selectors for variants with atrules', () => { + let config = {} + let context = createContext(resolveConfig(config)) + + let variants = context.getVariants() + + let variant = variants.find((v) => v.name === 'supports') + expect(variant.selectors({ value: 'display:grid' })).toEqual(['@supports (display:grid)']) + expect(variant.selectors({ value: 'aspect-ratio' })).toEqual([ + '@supports (aspect-ratio: var(--tw))', + ]) +}) + +it('should provide selectors for custom plugins that do a combination of parallel variants with modifiers with arbitrary values and with atrules', () => { + let config = { + plugins: [ + function ({ matchVariant }) { + matchVariant('foo', (value, { modifier }) => { + return [ + ` @supports (foo: ${modifier}) { @media (width <= 400px) { &:hover } } `, - `.${modifier}\\/${value} &:focus`, - ] - }) - }, - ], - } - let context = createContext(resolveConfig(config)) + `.${modifier}\\/${value} &:focus`, + ] + }) + }, + ], + } + let context = createContext(resolveConfig(config)) - let variants = context.getVariants() + let variants = context.getVariants() - let variant = variants.find((v) => v.name === 'foo') - expect(variant.selectors({ modifier: 'bar', value: 'baz' })).toEqual([ - '@supports (foo: bar) { @media (width <= 400px) { &:hover } }', - '.bar\\/baz &:focus', - ]) - }) - - it('should work for plugins that still use the modifySelectors API', () => { - let config = { - plugins: [ - function ({ addVariant }) { - addVariant('foo', ({ modifySelectors, container }) => { - // Manually mutating the selector - modifySelectors(({ selector }) => { - return selectorParser((selectors) => { - selectors.walkClasses((classNode) => { - classNode.value = `foo:${classNode.value}` - classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) - }) - }).processSync(selector) - }) - - // Manually wrap in supports query - let wrapper = postcss.atRule({ name: 'supports', params: 'display: grid' }) - let nodes = container.nodes - container.removeAll() - wrapper.append(nodes) - container.append(wrapper) - }) - }, - ], - } - let context = createContext(resolveConfig(config)) - - let variants = context.getVariants() - - let variant = variants.find((v) => v.name === 'foo') - expect(variant.selectors({})).toEqual(['@supports (display: grid) { .foo .foo\\:& }']) - }) - - it('should special case the `@`', () => { - let config = { - plugins: [ - ({ matchVariant }) => { - matchVariant( - '@', - (value, { modifier }) => `@container ${modifier ?? ''} (min-width: ${value})`, - { - modifiers: 'any', - values: { - xs: '20rem', - sm: '24rem', - md: '28rem', - lg: '32rem', - xl: '36rem', - '2xl': '42rem', - '3xl': '48rem', - '4xl': '56rem', - '5xl': '64rem', - '6xl': '72rem', - '7xl': '80rem', - }, - } - ) - }, - ], - } - let context = createContext(resolveConfig(config)) - - let variants = context.getVariants() - - let variant = variants.find((v) => v.name === '@') - expect(variant).toEqual({ - name: '@', - isArbitrary: true, - hasDash: false, - values: expect.any(Array), - selectors: expect.any(Function), - }) - expect(variant.selectors({ value: 'xs', modifier: 'foo' })).toEqual([ - '@container foo (min-width: 20rem)', - ]) - }) + let variant = variants.find((v) => v.name === 'foo') + expect(variant.selectors({ modifier: 'bar', value: 'baz' })).toEqual([ + '@supports (foo: bar) { @media (width <= 400px) { &:hover } }', + '.bar\\/baz &:focus', + ]) +}) + +it('should work for plugins that still use the modifySelectors API', () => { + let config = { + plugins: [ + function ({ addVariant }) { + addVariant('foo', ({ modifySelectors, container }) => { + // Manually mutating the selector + modifySelectors(({ selector }) => { + return selectorParser((selectors) => { + selectors.walkClasses((classNode) => { + classNode.value = `foo:${classNode.value}` + classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) + }) + }).processSync(selector) + }) + + // Manually wrap in supports query + let wrapper = postcss.atRule({ name: 'supports', params: 'display: grid' }) + let nodes = container.nodes + container.removeAll() + wrapper.append(nodes) + container.append(wrapper) + }) + }, + ], + } + let context = createContext(resolveConfig(config)) + + let variants = context.getVariants() + + let variant = variants.find((v) => v.name === 'foo') + expect(variant.selectors({})).toEqual(['@supports (display: grid) { .foo .foo\\:& }']) +}) + +it('should special case the `@`', () => { + let config = { + plugins: [ + ({ matchVariant }) => { + matchVariant( + '@', + (value, { modifier }) => `@container ${modifier ?? ''} (min-width: ${value})`, + { + modifiers: 'any', + values: { + xs: '20rem', + sm: '24rem', + md: '28rem', + lg: '32rem', + xl: '36rem', + '2xl': '42rem', + '3xl': '48rem', + '4xl': '56rem', + '5xl': '64rem', + '6xl': '72rem', + '7xl': '80rem', + }, + } + ) + }, + ], + } + let context = createContext(resolveConfig(config)) + + let variants = context.getVariants() + + let variant = variants.find((v) => v.name === '@') + expect(variant).toEqual({ + name: '@', + isArbitrary: true, + hasDash: false, + values: expect.any(Array), + selectors: expect.any(Function), + }) + expect(variant.selectors({ value: 'xs', modifier: 'foo' })).toEqual([ + '@container foo (min-width: 20rem)', + ]) }) diff --git a/tests/import-processing.test.js b/tests/import-processing.test.js index 962b7b28c..ef59be348 100644 --- a/tests/import-processing.test.js +++ b/tests/import-processing.test.js @@ -1,79 +1,76 @@ -import { html, css, run, crosscheck } from './util/run' +import { html, css, run } from './util/run' -crosscheck(({ oxide, stable }) => { - stable.test.todo('Import processing is an oxide engine feature') - oxide.describe('import processing', () => { - it('should be possible to import another css file', async () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, +describe('import processing', () => { + it('should be possible to import another css file', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @import './import-processing-a.css'; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; + } + `) + }) + + it('should be possible to import another css file after @tailwind directive', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + @import './import-processing-b.css'; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; } - let input = css` - @import './import-processing-a.css'; - ` + .foo { + color: red; + } + `) + }) - let result = await run(input, config) + it('should be possible to add @config before @import statements', async () => { + let input = css` + @config "./import-processing-c.js"; + @import './import-processing-c.css'; + ` - expect(result.css).toMatchFormattedCss(css` - .underline { - text-decoration-line: underline; - } - `) - }) + let result = await run(input) - it('should be possible to import another css file after @tailwind directive', async () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, + expect(result.css).toMatchFormattedCss(css` + .underline { + text-decoration-line: underline; } - let input = css` - @tailwind utilities; - - @import './import-processing-b.css'; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .underline { - text-decoration-line: underline; - } - - .foo { - color: red; - } - `) - }) - - it('should be possible to add @config before @import statements', async () => { - let input = css` - @config "./import-processing-c.js"; - @import './import-processing-c.css'; - ` - - let result = await run(input) - - expect(result.css).toMatchFormattedCss(css` - .underline { - text-decoration-line: underline; - } - - .foo { - color: red; - } - `) - }) + .foo { + color: red; + } + `) }) }) diff --git a/tests/import-syntax.test.js b/tests/import-syntax.test.js index 992ef81d5..99f5163f7 100644 --- a/tests/import-syntax.test.js +++ b/tests/import-syntax.test.js @@ -1,129 +1,82 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('using @import instead of @tailwind', () => { - let config = { - content: [ - { - raw: html` -

Hello world!

-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addBase }) { - addBase({ - h1: { - fontSize: '32px', - }, - }) - }, - ], - } +test('using @import instead of @tailwind', () => { + let config = { + content: [ + { + raw: html` +

Hello world!

+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addBase }) { + addBase({ + h1: { + fontSize: '32px', + }, + }) + }, + ], + } - let input = css` - @import 'tailwindcss/base'; - @import 'tailwindcss/components'; - @import 'tailwindcss/utilities'; - ` + let input = css` + @import 'tailwindcss/base'; + @import 'tailwindcss/components'; + @import 'tailwindcss/utilities'; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - h1 { - font-size: 32px; - } - ${defaults} + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + h1 { + font-size: 32px; + } + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { .container { - width: 100%; + max-width: 640px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .mt-6 { - margin-top: 1.5rem; - } - .bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - @media (min-width: 768px) { - .md\:hover\:text-center:hover { - text-align: center; - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - h1 { - font-size: 32px; - } - ${defaults} + } + @media (min-width: 768px) { .container { - width: 100%; + max-width: 768px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; } - @media (min-width: 768px) { - .container { - max-width: 768px; - } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } + } + .mt-6 { + margin-top: 1.5rem; + } + .bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + @media (min-width: 768px) { + .md\:hover\:text-center:hover { + text-align: center; } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .mt-6 { - margin-top: 1.5rem; - } - .bg-black { - background-color: #000; - } - @media (min-width: 768px) { - .md\:hover\:text-center:hover { - text-align: center; - } - } - `) - }) + } + `) }) }) diff --git a/tests/important-boolean.test.js b/tests/important-boolean.test.js index 895ca053c..d66f21edc 100644 --- a/tests/important-boolean.test.js +++ b/tests/important-boolean.test.js @@ -2,230 +2,228 @@ import fs from 'fs' import path from 'path' import * as sharedState from '../src/lib/sharedState' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('important boolean', () => { - let config = { - important: true, - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents, addUtilities }) { - addComponents( - { - '.btn': { - button: 'yes', - }, +test('important boolean', () => { + let config = { + important: true, + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents, addUtilities }) { + addComponents( + { + '.btn': { + button: 'yes', }, - { respectImportant: true } - ) - addComponents( - { - '@font-face': { - 'font-family': 'Inter', - }, - '@page': { - margin: '1cm', - }, + }, + { respectImportant: true } + ) + addComponents( + { + '@font-face': { + 'font-family': 'Inter', }, - { respectImportant: true } - ) - addUtilities( - { - '.custom-util': { - button: 'no', - }, + '@page': { + margin: '1cm', }, - { respectImportant: false } - ) - }, - ], + }, + { respectImportant: true } + ) + addUtilities( + { + '.custom-util': { + button: 'no', + }, + }, + { respectImportant: false } + ) + }, + ], + } + + let input = css` + @tailwind base; + @tailwind components; + @layer components { + .custom-component { + @apply font-bold; + } + .custom-important-component { + @apply text-center !important; + } } + @tailwind utilities; + ` - let input = css` - @tailwind base; - @tailwind components; - @layer components { - .custom-component { - @apply font-bold; - } - .custom-important-component { - @apply text-center !important; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { + .container { + max-width: 640px; } } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + .btn { + button: yes !important; + } + @font-face { + font-family: Inter; + } + @page { + margin: 1cm; + } + .custom-component { + font-weight: 700; + } + .custom-important-component { + text-align: center !important; + } + @keyframes spin { + to { + transform: rotate(360deg); + } + } + .animate-spin { + animation: 1s linear infinite spin !important; + } + .font-bold { + font-weight: 700 !important; + } + .custom-util { + button: no; + } + .group:hover .group-hover\:focus-within\:text-left:focus-within { + text-align: left !important; + } + :is([dir='rtl'] .rtl\:active\:text-center:active) { + text-align: center !important; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe\:hover\:text-center:hover { + text-align: center !important; + } + } + :is(.dark .dark\:focus\:text-left:focus) { + text-align: left !important; + } + @media (min-width: 768px) { + .md\:hover\:text-right:hover { + text-align: right !important; + } + } + `) + }) +}) + +// This is in a describe block so we can use `afterEach` :) +describe('duplicate elision', () => { + let filePath = path.resolve(__dirname, './important-boolean-duplicates.test.html') + + afterEach(async () => await fs.promises.unlink(filePath)) + + test('important rules are not duplicated when rebuilding', async () => { + let config = { + important: true, + content: [filePath], + } + + await fs.promises.writeFile( + config.content[0], + html` +
+
+ ` + ) + + let input = css` @tailwind utilities; ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .container { - width: 100%; - } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .btn { - button: yes !important; - } - @font-face { - font-family: Inter; - } - @page { - margin: 1cm; - } - .custom-component { - font-weight: 700; - } - .custom-important-component { - text-align: center !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .animate-spin { - animation: 1s linear infinite spin !important; - } - .font-bold { - font-weight: 700 !important; - } - .custom-util { - button: no; - } - .group:hover .group-hover\:focus-within\:text-left:focus-within { - text-align: left !important; - } - :is([dir='rtl'] .rtl\:active\:text-center:active) { - text-align: center !important; - } - @media (prefers-reduced-motion: no-preference) { - .motion-safe\:hover\:text-center:hover { - text-align: center !important; - } - } - :is(.dark .dark\:focus\:text-left:focus) { - text-align: left !important; - } - @media (min-width: 768px) { - .md\:hover\:text-right:hover { - text-align: right !important; - } - } - `) - }) - }) + let result = await run(input, config) + let allContexts = Array.from(sharedState.contextMap.values()) - // This is in a describe block so we can use `afterEach` :) - describe('duplicate elision', () => { - let filePath = path.resolve(__dirname, './important-boolean-duplicates.test.html') + let context = allContexts[allContexts.length - 1] - afterEach(async () => await fs.promises.unlink(filePath)) + let ruleCacheSize1 = context.ruleCache.size - test('important rules are not duplicated when rebuilding', async () => { - let config = { - important: true, - content: [filePath], + expect(result.css).toMatchFormattedCss(css` + .ml-2 { + margin-left: 0.5rem !important; } + .ml-4 { + margin-left: 1rem !important; + } + `) - await fs.promises.writeFile( - config.content[0], - html` -
-
- ` - ) - - let input = css` - @tailwind utilities; + await fs.promises.writeFile( + config.content[0], + html` +
+
` + ) - let result = await run(input, config) - let allContexts = Array.from(sharedState.contextMap.values()) + result = await run(input, config) - let context = allContexts[allContexts.length - 1] + let ruleCacheSize2 = context.ruleCache.size - let ruleCacheSize1 = context.ruleCache.size + expect(result.css).toMatchFormattedCss(css` + .ml-2 { + margin-left: 0.5rem !important; + } + .ml-4 { + margin-left: 1rem !important; + } + .ml-6 { + margin-left: 1.5rem !important; + } + `) - expect(result.css).toMatchFormattedCss(css` - .ml-2 { - margin-left: 0.5rem !important; - } - .ml-4 { - margin-left: 1rem !important; - } - `) - - await fs.promises.writeFile( - config.content[0], - html` -
-
- ` - ) - - result = await run(input, config) - - let ruleCacheSize2 = context.ruleCache.size - - expect(result.css).toMatchFormattedCss(css` - .ml-2 { - margin-left: 0.5rem !important; - } - .ml-4 { - margin-left: 1rem !important; - } - .ml-6 { - margin-left: 1.5rem !important; - } - `) - - // The rule cache was effectively doubling in size previously - // because the rule cache was never de-duped - // This ensures this behavior doesn't return - expect(ruleCacheSize2 - ruleCacheSize1).toBeLessThan(10) - }) + // The rule cache was effectively doubling in size previously + // because the rule cache was never de-duped + // This ensures this behavior doesn't return + expect(ruleCacheSize2 - ruleCacheSize1).toBeLessThan(10) }) }) diff --git a/tests/important-modifier-prefix.test.js b/tests/important-modifier-prefix.test.js index 782ec809e..2c6a8bb62 100644 --- a/tests/important-modifier-prefix.test.js +++ b/tests/important-modifier-prefix.test.js @@ -1,79 +1,77 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('important modifier with prefix', () => { - let config = { - important: false, - prefix: 'tw-', - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
`, - }, - ], - corePlugins: { preflight: false }, - } +test('important modifier with prefix', () => { + let config = { + important: false, + prefix: 'tw-', + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .\!tw-container { + width: 100% !important; + } + @media (min-width: 640px) { .\!tw-container { - width: 100% !important; + max-width: 640px !important; } - @media (min-width: 640px) { - .\!tw-container { - max-width: 640px !important; - } + } + @media (min-width: 768px) { + .\!tw-container { + max-width: 768px !important; } - @media (min-width: 768px) { - .\!tw-container { - max-width: 768px !important; - } + } + @media (min-width: 1024px) { + .\!tw-container { + max-width: 1024px !important; } - @media (min-width: 1024px) { - .\!tw-container { - max-width: 1024px !important; - } + } + @media (min-width: 1280px) { + .\!tw-container { + max-width: 1280px !important; } - @media (min-width: 1280px) { - .\!tw-container { - max-width: 1280px !important; - } + } + @media (min-width: 1536px) { + .\!tw-container { + max-width: 1536px !important; } - @media (min-width: 1536px) { - .\!tw-container { - max-width: 1536px !important; - } + } + .\!tw-font-bold { + font-weight: 700 !important; + } + .hover\:\!tw-text-center:hover { + text-align: center !important; + } + @media (min-width: 1024px) { + .lg\:\!tw-opacity-50 { + opacity: 0.5 !important; } - .\!tw-font-bold { - font-weight: 700 !important; + } + @media (min-width: 1280px) { + .xl\:focus\:disabled\:\!tw-float-right:disabled:focus { + float: right !important; } - .hover\:\!tw-text-center:hover { - text-align: center !important; - } - @media (min-width: 1024px) { - .lg\:\!tw-opacity-50 { - opacity: 0.5 !important; - } - } - @media (min-width: 1280px) { - .xl\:focus\:disabled\:\!tw-float-right:disabled:focus { - float: right !important; - } - } - `) - }) + } + `) }) }) diff --git a/tests/important-modifier.test.js b/tests/important-modifier.test.js index 6d30fd0bc..c736951d0 100644 --- a/tests/important-modifier.test.js +++ b/tests/important-modifier.test.js @@ -1,153 +1,151 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('important modifier', () => { - let config = { - important: false, - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ theme, matchUtilities, addComponents }) { - matchUtilities( - { - 'custom-parent': (value) => { - return { - '.custom-child': { - margin: value, - }, - } - }, +test('important modifier', () => { + let config = { + important: false, + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ theme, matchUtilities, addComponents }) { + matchUtilities( + { + 'custom-parent': (value) => { + return { + '.custom-child': { + margin: value, + }, + } }, - { values: theme('spacing') } - ) - addComponents({ - '.btn': { - '&.disabled, &:disabled': { - color: 'gray', - }, + }, + { values: theme('spacing') } + ) + addComponents({ + '.btn': { + '&.disabled, &:disabled': { + color: 'gray', }, - }) - }, - ], - } + }, + }) + }, + ], + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\!container { + width: 100% !important; + } + @media (min-width: 640px) { .\!container { - width: 100% !important; + max-width: 640px !important; } - @media (min-width: 640px) { - .\!container { - max-width: 640px !important; - } + } + @media (min-width: 768px) { + .\!container { + max-width: 768px !important; } - @media (min-width: 768px) { - .\!container { - max-width: 768px !important; - } + } + @media (min-width: 1024px) { + .\!container { + max-width: 1024px !important; } - @media (min-width: 1024px) { - .\!container { - max-width: 1024px !important; - } + } + @media (min-width: 1280px) { + .\!container { + max-width: 1280px !important; } - @media (min-width: 1280px) { - .\!container { - max-width: 1280px !important; - } + } + @media (min-width: 1536px) { + .\!container { + max-width: 1536px !important; } - @media (min-width: 1536px) { - .\!container { - max-width: 1536px !important; - } + } + .btn.disabled, + .btn:disabled { + color: gray; + } + .btn.\!disabled { + color: gray !important; + } + .\!font-bold { + font-weight: 700 !important; + } + .\!custom-parent-5 .custom-child { + margin: 1.25rem !important; + } + .hover\:\!text-center:hover { + text-align: center !important; + } + @media (min-width: 1024px) { + .lg\:\!opacity-50 { + opacity: 0.5 !important; } - .btn.disabled, - .btn:disabled { - color: gray; + } + @media (min-width: 1280px) { + .xl\:focus\:disabled\:\!float-right:disabled:focus { + float: right !important; } - .btn.\!disabled { - color: gray !important; - } - .\!font-bold { - font-weight: 700 !important; - } - .\!custom-parent-5 .custom-child { - margin: 1.25rem !important; - } - .hover\:\!text-center:hover { - text-align: center !important; - } - @media (min-width: 1024px) { - .lg\:\!opacity-50 { - opacity: 0.5 !important; - } - } - @media (min-width: 1280px) { - .xl\:focus\:disabled\:\!float-right:disabled:focus { - float: right !important; - } - } - `) - }) - }) - - test('the important modifier works on utilities using :where()', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents }) { - addComponents({ - ':where(.btn)': { - backgroundColor: '#00f', - }, - }) - }, - ], - } - - let input = css` - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - :where(.\!btn) { - background-color: #00f !important; - } - :where(.btn) { - background-color: #00f; - } - :where(.hover\:btn:hover) { - background-color: #00f; - } - :where(.hover\:focus\:disabled\:\!btn:disabled:focus:hover) { - background-color: #00f !important; - } - `) - }) + } + `) + }) +}) + +test('the important modifier works on utilities using :where()', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents }) { + addComponents({ + ':where(.btn)': { + backgroundColor: '#00f', + }, + }) + }, + ], + } + + let input = css` + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + :where(.\!btn) { + background-color: #00f !important; + } + :where(.btn) { + background-color: #00f; + } + :where(.hover\:btn:hover) { + background-color: #00f; + } + :where(.hover\:focus\:disabled\:\!btn:disabled:focus:hover) { + background-color: #00f !important; + } + `) }) }) diff --git a/tests/important-selector.test.js b/tests/important-selector.test.js index 22edafb94..a5399bdf7 100644 --- a/tests/important-selector.test.js +++ b/tests/important-selector.test.js @@ -1,205 +1,195 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('important selector', () => { - let config = { - important: '#app', - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - function ({ addComponents, addUtilities }) { - addComponents( - { - '.btn': { - button: 'yes', - }, +test('important selector', () => { + let config = { + important: '#app', + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ addComponents, addUtilities }) { + addComponents( + { + '.btn': { + button: 'yes', }, - { respectImportant: true } - ) - addComponents( - { - '@font-face': { - 'font-family': 'Inter', - }, - '@page': { - margin: '1cm', - }, + }, + { respectImportant: true } + ) + addComponents( + { + '@font-face': { + 'font-family': 'Inter', }, - { respectImportant: true } - ) - addUtilities( - { - '.custom-util': { - button: 'no', - }, + '@page': { + margin: '1cm', }, - { respectImportant: false } - ) - }, - ], + }, + { respectImportant: true } + ) + addUtilities( + { + '.custom-util': { + button: 'no', + }, + }, + { respectImportant: false } + ) + }, + ], + } + + let input = css` + @tailwind base; + @tailwind components; + @layer components { + .custom-component { + @apply font-bold; + } + .custom-important-component { + @apply text-center !important; + } } + @tailwind utilities; + ` - let input = css` - @tailwind base; - @tailwind components; - @layer components { - .custom-component { - @apply font-bold; - } - .custom-important-component { - @apply text-center !important; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { + .container { + max-width: 640px; } } - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} + @media (min-width: 768px) { .container { - width: 100%; + max-width: 768px; } - @media (min-width: 640px) { - .container { - max-width: 640px; - } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; } - @media (min-width: 768px) { - .container { - max-width: 768px; - } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } + } + #app .btn { + button: yes; + } + @font-face { + font-family: Inter; + } + @page { + margin: 1cm; + } + .custom-component { + font-weight: 700; + } + .custom-important-component { + text-align: center !important; + } + @keyframes spin { + to { + transform: rotate(360deg); } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - #app .btn { - button: yes; - } - @font-face { - font-family: Inter; - } - @page { - margin: 1cm; - } - .custom-component { - font-weight: 700; - } - .custom-important-component { - text-align: center !important; - } - @keyframes spin { - to { - transform: rotate(360deg); - } - } - #app :is(.animate-spin) { - animation: 1s linear infinite spin; - } - #app :is(.font-bold) { - font-weight: 700; - } - .custom-util { - button: no; - } - #app :is(.group:hover .group-hover\:focus-within\:text-left:focus-within) { - text-align: left; - } - #app :is(:is([dir='rtl'] .rtl\:active\:text-center:active)) { + } + #app :is(.animate-spin) { + animation: 1s linear infinite spin; + } + #app :is(.font-bold) { + font-weight: 700; + } + .custom-util { + button: no; + } + #app :is(.group:hover .group-hover\:focus-within\:text-left:focus-within) { + text-align: left; + } + #app :is(:is([dir='rtl'] .rtl\:active\:text-center:active)) { + text-align: center; + } + @media (prefers-reduced-motion: no-preference) { + #app :is(.motion-safe\:hover\:text-center:hover) { text-align: center; } - @media (prefers-reduced-motion: no-preference) { - #app :is(.motion-safe\:hover\:text-center:hover) { - text-align: center; - } + } + #app :is(.dark .dark\:before\:underline):before { + content: var(--tw-content); + text-decoration-line: underline; + } + #app :is(:is(.dark .dark\:focus\:text-left:focus)) { + text-align: left; + } + @media (min-width: 768px) { + #app :is(.md\:hover\:text-right:hover) { + text-align: right; } - #app :is(.dark .dark\:before\:underline):before { - content: var(--tw-content); - text-decoration-line: underline; - } - #app :is(:is(.dark .dark\:focus\:text-left:focus)) { - text-align: left; - } - @media (min-width: 768px) { - #app :is(.md\:hover\:text-right:hover) { - text-align: right; - } - } - #app - :is( - [dir='rtl'] :is(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) - )::file-selector-button:hover { - background-color: #000; - } - `) - }) - }) - - test('pseudo-elements are appended after the `:is()`', () => { - let config = { - important: '#app', - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - ${defaults} - #app :is(.dark .dark\:before\:bg-black)::before { - content: var(--tw-content); - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - ${defaults} - #app :is(.dark .dark\:before\:bg-black)::before { - content: var(--tw-content); - background-color: #000; - } - `) - }) + } + #app + :is( + [dir='rtl'] :is(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) + )::file-selector-button:hover { + background-color: #000; + } + `) + }) +}) + +test('pseudo-elements are appended after the `:is()`', () => { + let config = { + important: '#app', + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + #app :is(.dark .dark\:before\:flex)::before { + content: var(--tw-content); + display: flex; + } + `) }) }) diff --git a/tests/kitchen-sink.test.js b/tests/kitchen-sink.test.js index 3b02c8966..8f4b7cae2 100644 --- a/tests/kitchen-sink.test.js +++ b/tests/kitchen-sink.test.js @@ -1,1374 +1,812 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('it works', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+test('it works', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- - `, + things: Array /* PropType */, + }, + setup: () => { + const count = ref(0) + // Weird regex-looking stuff that once caused a stack overflow in candidatePermutations + const pattern = ' ]-[] ' + return { + count, + stuff: [] /* string[] | undefined */, + } + }, + }) + + `, + }, + ], + corePlugins: { preflight: false }, + theme: { + extend: { + screens: { + range: { min: '1280px', max: '1535px' }, + multi: [{ min: '640px', max: '767px' }, { max: '868px' }], }, - ], - corePlugins: { preflight: false }, - theme: { - extend: { - screens: { - range: { min: '1280px', max: '1535px' }, - multi: [{ min: '640px', max: '767px' }, { max: '868px' }], - }, - gradientColorStops: { - foo: '#bada55', - }, - backgroundImage: { - 'hero--home-1': "url('/images/homepage-1.jpg')", - }, + gradientColorStops: { + foo: '#bada55', + }, + backgroundImage: { + 'hero--home-1': "url('/images/homepage-1.jpg')", }, }, - plugins: [ - function ({ addVariant }) { - addVariant( - 'foo', - ({ container }) => { - container.walkRules((rule) => { - rule.selector = `.foo\\:${rule.selector.slice(1)}` - rule.walkDecls((decl) => { - decl.important = true - }) + }, + plugins: [ + function ({ addVariant }) { + addVariant( + 'foo', + ({ container }) => { + container.walkRules((rule) => { + rule.selector = `.foo\\:${rule.selector.slice(1)}` + rule.walkDecls((decl) => { + decl.important = true }) + }) + }, + { before: 'sm' } + ) + }, + function ({ addUtilities, addBase, theme }) { + addBase({ + h1: { + fontSize: theme('fontSize.2xl'), + fontWeight: theme('fontWeight.bold'), + '&:first-child': { + marginTop: '0px', }, - { before: 'sm' } - ) - }, - function ({ addUtilities, addBase, theme }) { - addBase({ - h1: { - fontSize: theme('fontSize.2xl'), - fontWeight: theme('fontWeight.bold'), - '&:first-child': { - marginTop: '0px', - }, + }, + }) + addUtilities( + { + '.magic-none': { + magic: 'none', }, - }) - addUtilities( - { - '.magic-none': { - magic: 'none', - }, - '.magic-tons': { - magic: 'tons', - }, + '.magic-tons': { + magic: 'tons', }, - ['responsive', 'hover'] - ) - }, - ], - } + }, + ['responsive', 'hover'] + ) + }, + ], + } - let input = css` - @layer utilities { - .custom-util { - background: #abcdef; - } - *, - ::before, - ::after, - ::backdrop { - margin: 10px; - } + let input = css` + @layer utilities { + .custom-util { + background: #abcdef; } - @layer components { - .test-apply-font-variant { - @apply ordinal tabular-nums; - } - .custom-component { - background: #123456; - } - *, - ::before, - ::after, - ::backdrop { - padding: 5px; - } - .foo .bg-black { - appearance: none; - } + *, + ::before, + ::after, + ::backdrop { + margin: 10px; } - @layer base { - div { - background: #654321; - } + } + @layer components { + .test-apply-font-variant { + @apply ordinal tabular-nums; } + .custom-component { + background: #123456; + } + *, + ::before, + ::after, + ::backdrop { + padding: 5px; + } + .foo .bg-black { + appearance: none; + } + } + @layer base { + div { + background: #654321; + } + } + .theme-test { + font-family: theme('fontFamily.sans'); + color: theme('colors.blue.500'); + } + @screen lg { + .screen-test { + color: purple; + } + } + .apply-1 { + @apply mt-6; + } + .apply-2 { + @apply mt-6; + } + .apply-test { + @apply mt-6 bg-pink-500 hover:font-bold focus:hover:font-bold sm:bg-green-500 sm:focus:even:bg-pink-200; + } + .apply-components { + @apply container mx-auto; + } + .drop-empty-rules { + @apply hover:font-bold; + } + .apply-group { + @apply group-hover:font-bold; + } + .apply-dark-mode { + @apply dark:font-bold; + } + .apply-with-existing:hover { + @apply font-normal sm:bg-green-500; + } + .multiple, + .selectors { + @apply font-bold group-hover:font-normal; + } + .list { + @apply space-y-4; + } + .nested { + .example { + @apply font-bold hover:font-normal; + } + } + .apply-order-a { + @apply m-5 mt-6; + } + .apply-order-b { + @apply m-5 mt-6; + } + .apply-dark-group-example-a { + @apply dark:group-hover:bg-green-500; + } + .crazy-example { + @apply sm:motion-safe:group-active:focus:opacity-10; + } + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` .theme-test { - font-family: theme('fontFamily.sans'); - color: theme('colors.blue.500'); + color: #3b82f6; + font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, + Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, + Segoe UI Symbol, Noto Color Emoji; } - @screen lg { + @media (min-width: 1024px) { .screen-test { color: purple; } } - .apply-1 { - @apply mt-6; - } + .apply-1, .apply-2 { - @apply mt-6; + margin-top: 1.5rem; } .apply-test { - @apply mt-6 bg-pink-500 hover:font-bold focus:hover:font-bold sm:bg-green-500 sm:focus:even:bg-pink-200; + --tw-bg-opacity: 1; + background-color: rgb(236 72 153 / var(--tw-bg-opacity)); + margin-top: 1.5rem; + } + .apply-test:hover, + .apply-test:hover:focus { + font-weight: 700; + } + @media (min-width: 640px) { + .apply-test { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); + } + .apply-test:nth-child(2n):focus { + --tw-bg-opacity: 1; + background-color: rgb(251 207 232 / var(--tw-bg-opacity)); + } } .apply-components { - @apply container mx-auto; + width: 100%; } - .drop-empty-rules { - @apply hover:font-bold; + @media (min-width: 640px) { + .apply-components { + max-width: 640px; + } } - .apply-group { - @apply group-hover:font-bold; + @media (min-width: 768px) { + .apply-components { + max-width: 768px; + } } - .apply-dark-mode { - @apply dark:font-bold; + @media (min-width: 1024px) { + .apply-components { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .apply-components { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .apply-components { + max-width: 1536px; + } + } + .apply-components { + margin-left: auto; + margin-right: auto; + } + .drop-empty-rules:hover, + .group:hover .apply-group, + :is(.dark .apply-dark-mode) { + font-weight: 700; } .apply-with-existing:hover { - @apply font-normal sm:bg-green-500; + font-weight: 400; + } + @media (min-width: 640px) { + .apply-with-existing:hover { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); + } } .multiple, .selectors { - @apply font-bold group-hover:font-normal; + font-weight: 700; } - .list { - @apply space-y-4; + .group:hover .multiple, + .group:hover .selectors { + font-weight: 400; } - .nested { - .example { - @apply font-bold hover:font-normal; - } + .list > :not([hidden]) ~ :not([hidden]) { + --tw-space-y-reverse: 0; + margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); + margin-bottom: calc(1rem * var(--tw-space-y-reverse)); } - .apply-order-a { - @apply m-5 mt-6; + .nested .example { + font-weight: 700; } + .nested .example:hover { + font-weight: 400; + } + .apply-order-a, .apply-order-b { - @apply m-5 mt-6; + margin: 1.5rem 1.25rem 1.25rem; } - .apply-dark-group-example-a { - @apply dark:group-hover:bg-green-500; + :is(.dark .group:hover .apply-dark-group-example-a) { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } - .crazy-example { - @apply sm:motion-safe:group-active:focus:opacity-10; + @media (min-width: 640px) { + @media (prefers-reduced-motion: no-preference) { + .group:active .crazy-example:focus { + opacity: 0.1; + } + } } - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .theme-test { - color: #3b82f6; - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, - Segoe UI Symbol, Noto Color Emoji; - } - @media (min-width: 1024px) { - .screen-test { - color: purple; - } - } - .apply-1, - .apply-2 { - margin-top: 1.5rem; - } - .apply-test { - --tw-bg-opacity: 1; - background-color: rgb(236 72 153 / var(--tw-bg-opacity)); - margin-top: 1.5rem; - } - .apply-test:hover, - .apply-test:hover:focus { - font-weight: 700; - } - @media (min-width: 640px) { - .apply-test { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - .apply-test:nth-child(2n):focus { - --tw-bg-opacity: 1; - background-color: rgb(251 207 232 / var(--tw-bg-opacity)); - } - } - .apply-components { - width: 100%; - } - @media (min-width: 640px) { - .apply-components { - max-width: 640px; - } - } - @media (min-width: 768px) { - .apply-components { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .apply-components { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .apply-components { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .apply-components { - max-width: 1536px; - } - } - .apply-components { - margin-left: auto; - margin-right: auto; - } - .drop-empty-rules:hover, - .group:hover .apply-group, - :is(.dark .apply-dark-mode) { - font-weight: 700; - } - .apply-with-existing:hover { - font-weight: 400; - } - @media (min-width: 640px) { - .apply-with-existing:hover { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - } - .multiple, - .selectors { - font-weight: 700; - } - .group:hover .multiple, - .group:hover .selectors { - font-weight: 400; - } - .list > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); - } - .nested .example { - font-weight: 700; - } - .nested .example:hover { - font-weight: 400; - } - .apply-order-a, - .apply-order-b { - margin: 1.5rem 1.25rem 1.25rem; - } - :is(.dark .group:hover .apply-dark-group-example-a) { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - @media (min-width: 640px) { - @media (prefers-reduced-motion: no-preference) { - .group:active .crazy-example:focus { - opacity: 0.1; - } - } - } - h1 { - font-size: 1.5rem; - font-weight: 700; - } - h1:first-child { - margin-top: 0; - } - div { - background: #654321; - } - ${defaults} + h1 { + font-size: 1.5rem; + font-weight: 700; + } + h1:first-child { + margin-top: 0; + } + div { + background: #654321; + } + ${defaults} + .container { + width: 100%; + } + @media (min-width: 640px) { .container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .container { + max-width: 1536px; + } + } + .test-apply-font-variant { + --tw-ordinal: ordinal; + --tw-numeric-spacing: tabular-nums; + font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) + var(--tw-numeric-spacing) var(--tw-numeric-fraction); + } + .custom-component { + background: #123456; + } + *, + :before, + :after, + ::backdrop { + padding: 5px; + } + .foo .bg-black { + appearance: none; + } + .inset-6 { + inset: 1.5rem; + } + .inset-x-1 { + left: 0.25rem; + right: 0.25rem; + } + .end-8 { + inset-inline-end: 2rem; + } + .start-4 { + inset-inline-start: 1rem; + } + .mx-1 { + margin-left: 0.25rem; + margin-right: 0.25rem; + } + .me-8 { + margin-inline-end: 2rem; + } + .ms-4 { + margin-inline-start: 1rem; + } + .mt-6 { + margin-top: 1.5rem; + } + .line-clamp-2 { + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + } + .line-clamp-\[33\] { + -webkit-line-clamp: 33; + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + } + .line-clamp-\[var\(--line-clamp-variable\)\] { + -webkit-line-clamp: var(--line-clamp-variable); + -webkit-box-orient: vertical; + display: -webkit-box; + overflow: hidden; + } + .line-clamp-none { + -webkit-line-clamp: none; + -webkit-box-orient: horizontal; + display: block; + overflow: visible; + } + .scale-50 { + --tw-scale-x: 0.5; + --tw-scale-y: 0.5; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { + grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; + } + .rounded-e { + border-start-end-radius: 0.25rem; + border-end-end-radius: 0.25rem; + } + .rounded-s { + border-start-start-radius: 0.25rem; + border-end-start-radius: 0.25rem; + } + .rounded-es { + border-end-start-radius: 0.25rem; + } + .rounded-ss { + border-start-start-radius: 0.25rem; + } + .border-2 { + border-width: 2px; + } + .border-e-4 { + border-inline-end-width: 4px; + } + .border-s-0 { + border-inline-start-width: 0; + } + .border-black { + --tw-border-opacity: 1; + border-color: rgb(0 0 0 / var(--tw-border-opacity)); + } + .border-e-red-400 { + --tw-border-opacity: 1; + border-inline-end-color: rgb(248 113 113 / var(--tw-border-opacity)); + } + .border-s-green-500 { + --tw-border-opacity: 1; + border-inline-start-color: rgb(34 197 94 / var(--tw-border-opacity)); + } + .bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .bg-green-500 { + --tw-bg-opacity: 1; + background-color: rgb(34 197 94 / var(--tw-bg-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); + } + .bg-hero--home-1 { + background-image: url('/images/homepage-1.jpg'); + } + .from-foo { + --tw-gradient-from: #bada55 var(--tw-gradient-from-position); + --tw-gradient-to: #bada5500 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .px-1 { + padding-left: 0.25rem; + padding-right: 0.25rem; + } + .pe-8 { + padding-inline-end: 2rem; + } + .ps-4 { + padding-inline-start: 1rem; + } + .pt-6 { + padding-top: 1.5rem; + } + .text-center { + text-align: center; + } + .font-medium { + font-weight: 500; + } + .shadow-md { + --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; + --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), + 0 2px 4px -2px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .shadow-sm { + --tw-shadow: 0 1px 2px 0 #0000000d; + --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .magic-none { + magic: none; + } + .magic-tons { + magic: tons; + } + .custom-util { + background: #abcdef; + } + *, + :before, + :after, + ::backdrop { + margin: 10px; + } + .hover\:container:hover { + width: 100%; + } + @media (min-width: 640px) { + .hover\:container:hover { + max-width: 640px; + } + } + @media (min-width: 768px) { + .hover\:container:hover { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .hover\:container:hover { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .hover\:container:hover { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .hover\:container:hover { + max-width: 1536px; + } + } + @media (min-width: 640px) { + .sm\:container { width: 100%; } @media (min-width: 640px) { - .container { + .sm\:container { max-width: 640px; } } @media (min-width: 768px) { - .container { + .sm\:container { max-width: 768px; } } @media (min-width: 1024px) { - .container { + .sm\:container { max-width: 1024px; } } @media (min-width: 1280px) { - .container { + .sm\:container { max-width: 1280px; } } @media (min-width: 1536px) { - .container { + .sm\:container { max-width: 1536px; } } - .test-apply-font-variant { - --tw-ordinal: ordinal; + } + @media (min-width: 768px) { + .md\:container { + width: 100%; + } + @media (min-width: 640px) { + .md\:container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .md\:container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .md\:container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .md\:container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .md\:container { + max-width: 1536px; + } + } + } + .first\:pt-0:first-child { + padding-top: 0; + } + .hover\:scale-75:hover { + --tw-scale-x: 0.75; + --tw-scale-y: 0.75; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .hover\:font-bold:hover { + font-weight: 700; + } + .hover\:shadow-lg:hover { + --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; + --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), + 0 4px 6px -4px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .hover\:custom-util:hover { + background: #abcdef; + } + .focus\:font-normal:focus { + font-weight: 400; + } + .focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + .focus\:ring-blue-500:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); + } + .focus\:hover\:font-light:hover:focus { + font-weight: 300; + } + .disabled\:font-bold:disabled { + font-weight: 700; + } + .group:hover .group-hover\:opacity-100 { + opacity: 1; + } + .group:hover .group-hover\:custom-util { + background: #abcdef; + } + .group:active .group-active\:opacity-10 { + opacity: 0.1; + } + .foo\:custom-util, + .foo\:hover\:custom-util:hover { + background: #abcdef !important; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe\:transition { + transition-property: color, background-color, border-color, text-decoration-color, fill, + stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-duration: 0.15s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + } + .motion-safe\:custom-util { + background: #abcdef; + } + } + @media (prefers-reduced-motion: reduce) { + .motion-reduce\:transition { + transition-property: color, background-color, border-color, text-decoration-color, fill, + stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-duration: 0.15s; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + } + } + :is(.dark .dark\:custom-util) { + background: #abcdef; + } + @media (min-width: 640px) { + .sm\:text-center { + text-align: center; + } + .sm\:tabular-nums { --tw-numeric-spacing: tabular-nums; font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) var(--tw-numeric-spacing) var(--tw-numeric-fraction); } - .custom-component { - background: #123456; + .sm\:custom-util { + background: #abcdef; } - *, - :before, - :after, - ::backdrop { - padding: 5px; + @media (prefers-reduced-motion: no-preference) { + .group:active .sm\:motion-safe\:group-active\:focus\:opacity-10:focus { + opacity: 0.1; + } } - .foo .bg-black { - appearance: none; - } - .inset-6 { - inset: 1.5rem; - } - .inset-x-1 { - left: 0.25rem; - right: 0.25rem; - } - .end-8 { - inset-inline-end: 2rem; - } - .start-4 { - inset-inline-start: 1rem; - } - .mx-1 { - margin-left: 0.25rem; - margin-right: 0.25rem; - } - .me-8 { - margin-inline-end: 2rem; - } - .ms-4 { - margin-inline-start: 1rem; - } - .mt-6 { - margin-top: 1.5rem; - } - .line-clamp-2 { - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[33\] { - -webkit-line-clamp: 33; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[var\(--line-clamp-variable\)\] { - -webkit-line-clamp: var(--line-clamp-variable); - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-none { - -webkit-line-clamp: none; - -webkit-box-orient: horizontal; - display: block; - overflow: visible; - } - .scale-50 { - --tw-scale-x: 0.5; - --tw-scale-y: 0.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .rounded-e { - border-start-end-radius: 0.25rem; - border-end-end-radius: 0.25rem; - } - .rounded-s { - border-start-start-radius: 0.25rem; - border-end-start-radius: 0.25rem; - } - .rounded-es { - border-end-start-radius: 0.25rem; - } - .rounded-ss { - border-start-start-radius: 0.25rem; - } - .border-2 { - border-width: 2px; - } - .border-e-4 { - border-inline-end-width: 4px; - } - .border-s-0 { - border-inline-start-width: 0; - } - .border-black { - --tw-border-opacity: 1; - border-color: rgb(0 0 0 / var(--tw-border-opacity)); - } - .border-e-red-400 { - --tw-border-opacity: 1; - border-inline-end-color: rgb(248 113 113 / var(--tw-border-opacity)); - } - .border-s-green-500 { - --tw-border-opacity: 1; - border-inline-start-color: rgb(34 197 94 / var(--tw-border-opacity)); - } - .bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - .bg-green-500 { - --tw-bg-opacity: 1; - background-color: rgb(34 197 94 / var(--tw-bg-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - .bg-hero--home-1 { - background-image: url('/images/homepage-1.jpg'); - } - .from-foo { - --tw-gradient-from: #bada55 var(--tw-gradient-from-position); - --tw-gradient-to: #bada5500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .px-1 { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - .pe-8 { - padding-inline-end: 2rem; - } - .ps-4 { - padding-inline-start: 1rem; - } - .pt-6 { - padding-top: 1.5rem; - } - .text-center { + } + @media (min-width: 768px) { + .md\:text-center { text-align: center; } - .font-medium { - font-weight: 500; + .md\:opacity-50 { + opacity: 0.5; } - .shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .shadow-sm { + .md\:shadow-sm { --tw-shadow: 0 1px 2px 0 #0000000d; --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } - .magic-none { - magic: none; + .md\:hover\:border-r-blue-500\/30:hover { + border-right-color: #3b82f64d; } - .magic-tons { - magic: tons; - } - .custom-util { - background: #abcdef; - } - *, - :before, - :after, - ::backdrop { - margin: 10px; - } - .hover\:container:hover { - width: 100%; - } - @media (min-width: 640px) { - .hover\:container:hover { - max-width: 640px; - } - } - @media (min-width: 768px) { - .hover\:container:hover { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .hover\:container:hover { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .hover\:container:hover { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .hover\:container:hover { - max-width: 1536px; - } - } - @media (min-width: 640px) { - .sm\:container { - width: 100%; - } - @media (min-width: 640px) { - .sm\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .sm\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .sm\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .sm\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .sm\:container { - max-width: 1536px; - } - } - } - @media (min-width: 768px) { - .md\:container { - width: 100%; - } - @media (min-width: 640px) { - .md\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .md\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .md\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .md\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .md\:container { - max-width: 1536px; - } - } - } - .first\:pt-0:first-child { - padding-top: 0; - } - .hover\:scale-75:hover { - --tw-scale-x: 0.75; - --tw-scale-y: 0.75; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .hover\:font-bold:hover { - font-weight: 700; - } - .hover\:shadow-lg:hover { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .hover\:custom-util:hover { - background: #abcdef; - } - .focus\:font-normal:focus { - font-weight: 400; - } - .focus\:ring-2:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .focus\:ring-blue-500:focus { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(59 130 246 / var(--tw-ring-opacity)); - } - .focus\:hover\:font-light:hover:focus { - font-weight: 300; - } - .disabled\:font-bold:disabled { - font-weight: 700; - } - .group:hover .group-hover\:opacity-100 { - opacity: 1; - } - .group:hover .group-hover\:custom-util { - background: #abcdef; - } - .group:active .group-active\:opacity-10 { - opacity: 0.1; - } - .foo\:custom-util, - .foo\:hover\:custom-util:hover { - background: #abcdef !important; + .md\:hover\:opacity-20:hover { + opacity: 0.2; } @media (prefers-reduced-motion: no-preference) { - .motion-safe\:transition { + .md\:motion-safe\:hover\:transition:hover { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } - .motion-safe\:custom-util { - background: #abcdef; + :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { + background: #abcdef !important; } } - @media (prefers-reduced-motion: reduce) { - .motion-reduce\:transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - } - :is(.dark .dark\:custom-util) { - background: #abcdef; - } @media (min-width: 640px) { - .sm\:text-center { + .md\:sm\:text-center { text-align: center; } - .sm\:tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .sm\:custom-util { - background: #abcdef; - } - @media (prefers-reduced-motion: no-preference) { - .group:active .sm\:motion-safe\:group-active\:focus\:opacity-10:focus { - opacity: 0.1; - } - } } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:opacity-50 { - opacity: 0.5; - } - .md\:shadow-sm { - --tw-shadow: 0 1px 2px 0 #0000000d; - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .md\:hover\:border-r-blue-500\/30:hover { - border-right-color: #3b82f64d; - } - .md\:hover\:opacity-20:hover { - opacity: 0.2; - } - @media (prefers-reduced-motion: no-preference) { - .md\:motion-safe\:hover\:transition:hover { - transition-property: color, background-color, border-color, text-decoration-color, - fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { - background: #abcdef !important; - } - } - @media (min-width: 640px) { - .md\:sm\:text-center { - text-align: center; - } - } + } + @media (min-width: 1280px) and (max-width: 1535px) { + .range\:text-right { + text-align: right; } - @media (min-width: 1280px) and (max-width: 1535px) { - .range\:text-right { - text-align: right; - } + } + @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { + .multi\:text-left { + text-align: left; } - @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { - .multi\:text-left { - text-align: left; - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .theme-test { - color: #3b82f6; - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, - Segoe UI Symbol, Noto Color Emoji; - } - @media (min-width: 1024px) { - .screen-test { - color: purple; - } - } - .apply-1, - .apply-2 { - margin-top: 1.5rem; - } - .apply-test { - background-color: #ec4899; - margin-top: 1.5rem; - } - .apply-test:hover, - .apply-test:hover:focus { - font-weight: 700; - } - @media (min-width: 640px) { - .apply-test { - background-color: #22c55e; - } - .apply-test:nth-child(2n):focus { - background-color: #fbcfe8; - } - } - .apply-components { - width: 100%; - } - @media (min-width: 640px) { - .apply-components { - max-width: 640px; - } - } - @media (min-width: 768px) { - .apply-components { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .apply-components { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .apply-components { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .apply-components { - max-width: 1536px; - } - } - .apply-components { - margin-left: auto; - margin-right: auto; - } - .drop-empty-rules:hover, - .group:hover .apply-group, - :is(.dark .apply-dark-mode) { - font-weight: 700; - } - .apply-with-existing:hover { - font-weight: 400; - } - @media (min-width: 640px) { - .apply-with-existing:hover { - background-color: #22c55e; - } - } - .multiple, - .selectors { - font-weight: 700; - } - .group:hover .multiple, - .group:hover .selectors { - font-weight: 400; - } - .list > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(1rem * var(--tw-space-y-reverse)); - } - .nested .example { - font-weight: 700; - } - .nested .example:hover { - font-weight: 400; - } - .apply-order-a, - .apply-order-b { - margin: 1.5rem 1.25rem 1.25rem; - } - :is(.dark .group:hover .apply-dark-group-example-a) { - background-color: #22c55e; - } - @media (min-width: 640px) { - @media (prefers-reduced-motion: no-preference) { - .group:active .crazy-example:focus { - opacity: 0.1; - } - } - } - h1 { - font-size: 1.5rem; - font-weight: 700; - } - h1:first-child { - margin-top: 0; - } - div { - background: #654321; - } - ${defaults} - .container { - width: 100%; - } - @media (min-width: 640px) { - .container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .container { - max-width: 1536px; - } - } - .test-apply-font-variant { - --tw-ordinal: ordinal; - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .custom-component { - background: #123456; - } - *, - :before, - :after, - ::backdrop { - padding: 5px; - } - .foo .bg-black { - appearance: none; - } - .inset-6 { - inset: 1.5rem; - } - .inset-x-1 { - left: 0.25rem; - right: 0.25rem; - } - .end-8 { - inset-inline-end: 2rem; - } - .start-4 { - inset-inline-start: 1rem; - } - .mx-1 { - margin-left: 0.25rem; - margin-right: 0.25rem; - } - .me-8 { - margin-inline-end: 2rem; - } - .ms-4 { - margin-inline-start: 1rem; - } - .mt-6 { - margin-top: 1.5rem; - } - .line-clamp-2 { - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[33\] { - -webkit-line-clamp: 33; - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-\[var\(--line-clamp-variable\)\] { - -webkit-line-clamp: var(--line-clamp-variable); - -webkit-box-orient: vertical; - display: -webkit-box; - overflow: hidden; - } - .line-clamp-none { - -webkit-line-clamp: none; - -webkit-box-orient: horizontal; - display: block; - overflow: visible; - } - .scale-50 { - --tw-scale-x: 0.5; - --tw-scale-y: 0.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { - grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; - } - .rounded-e { - border-start-end-radius: 0.25rem; - border-end-end-radius: 0.25rem; - } - .rounded-s { - border-start-start-radius: 0.25rem; - border-end-start-radius: 0.25rem; - } - .rounded-es { - border-end-start-radius: 0.25rem; - } - .rounded-ss { - border-start-start-radius: 0.25rem; - } - .border-2 { - border-width: 2px; - } - .border-e-4 { - border-inline-end-width: 4px; - } - .border-s-0 { - border-inline-start-width: 0; - } - .border-black { - border-color: #000; - } - .border-e-red-400 { - border-inline-end-color: #f87171; - } - .border-s-green-500 { - border-inline-start-color: #22c55e; - } - .bg-black { - background-color: #000; - } - .bg-green-500 { - background-color: #22c55e; - } - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - .bg-hero--home-1 { - background-image: url('/images/homepage-1.jpg'); - } - .from-foo { - --tw-gradient-from: #bada55 var(--tw-gradient-from-position); - --tw-gradient-to: #bada5500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .px-1 { - padding-left: 0.25rem; - padding-right: 0.25rem; - } - .pe-8 { - padding-inline-end: 2rem; - } - .ps-4 { - padding-inline-start: 1rem; - } - .pt-6 { - padding-top: 1.5rem; - } - .text-center { - text-align: center; - } - .font-medium { - font-weight: 500; - } - .shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .shadow-sm { - --tw-shadow: 0 1px 2px 0 #0000000d; - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .magic-none { - magic: none; - } - .magic-tons { - magic: tons; - } - .custom-util { - background: #abcdef; - } - *, - :before, - :after, - ::backdrop { - margin: 10px; - } - .hover\:container:hover { - width: 100%; - } - @media (min-width: 640px) { - .hover\:container:hover { - max-width: 640px; - } - } - @media (min-width: 768px) { - .hover\:container:hover { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .hover\:container:hover { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .hover\:container:hover { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .hover\:container:hover { - max-width: 1536px; - } - } - @media (min-width: 640px) { - .sm\:container { - width: 100%; - } - @media (min-width: 640px) { - .sm\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .sm\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .sm\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .sm\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .sm\:container { - max-width: 1536px; - } - } - } - @media (min-width: 768px) { - .md\:container { - width: 100%; - } - @media (min-width: 640px) { - .md\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .md\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .md\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .md\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .md\:container { - max-width: 1536px; - } - } - } - .first\:pt-0:first-child { - padding-top: 0; - } - .hover\:scale-75:hover { - --tw-scale-x: 0.75; - --tw-scale-y: 0.75; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .hover\:font-bold:hover { - font-weight: 700; - } - .hover\:shadow-lg:hover { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .hover\:custom-util:hover { - background: #abcdef; - } - .focus\:font-normal:focus { - font-weight: 400; - } - .focus\:ring-2:focus { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .focus\:ring-blue-500:focus { - --tw-ring-color: #3b82f6; - } - .focus\:hover\:font-light:hover:focus { - font-weight: 300; - } - .disabled\:font-bold:disabled { - font-weight: 700; - } - .group:hover .group-hover\:opacity-100 { - opacity: 1; - } - .group:hover .group-hover\:custom-util { - background: #abcdef; - } - .group:active .group-active\:opacity-10 { - opacity: 0.1; - } - .foo\:custom-util, - .foo\:hover\:custom-util:hover { - background: #abcdef !important; - } - @media (prefers-reduced-motion: no-preference) { - .motion-safe\:transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - .motion-safe\:custom-util { - background: #abcdef; - } - } - @media (prefers-reduced-motion: reduce) { - .motion-reduce\:transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - } - :is(.dark .dark\:custom-util) { - background: #abcdef; - } - @media (min-width: 640px) { - .sm\:text-center { - text-align: center; - } - .sm\:tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); - } - .sm\:custom-util { - background: #abcdef; - } - @media (prefers-reduced-motion: no-preference) { - .group:active .sm\:motion-safe\:group-active\:focus\:opacity-10:focus { - opacity: 0.1; - } - } - } - @media (min-width: 768px) { - .md\:text-center { - text-align: center; - } - .md\:opacity-50 { - opacity: 0.5; - } - .md\:shadow-sm { - --tw-shadow: 0 1px 2px 0 #0000000d; - --tw-shadow-colored: 0 1px 2px 0 var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .md\:hover\:border-r-blue-500\/30:hover { - border-right-color: #3b82f64d; - } - .md\:hover\:opacity-20:hover { - opacity: 0.2; - } - @media (prefers-reduced-motion: no-preference) { - .md\:motion-safe\:hover\:transition:hover { - transition-property: color, background-color, border-color, text-decoration-color, - fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - } - :is(.dark .md\:dark\:motion-safe\:foo\:active\:custom-util:active) { - background: #abcdef !important; - } - } - @media (min-width: 640px) { - .md\:sm\:text-center { - text-align: center; - } - } - } - @media (min-width: 1280px) and (max-width: 1535px) { - .range\:text-right { - text-align: right; - } - } - @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { - .multi\:text-left { - text-align: left; - } - } - `) - }) + } + `) }) }) diff --git a/tests/layer-at-rules.test.js b/tests/layer-at-rules.test.js index db98bbeb5..1c4604835 100644 --- a/tests/layer-at-rules.test.js +++ b/tests/layer-at-rules.test.js @@ -1,321 +1,319 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - test('custom user-land utilities', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], +test('custom user-land utilities', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } + + let input = css` + @layer utilities { + .align-banana { + text-align: banana; + } } - let input = css` - @layer utilities { - .align-banana { - text-align: banana; - } + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer utilities { + .align-chocolate { + text-align: chocolate; } + } + ` - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer utilities { - .align-chocolate { - text-align: chocolate; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .uppercase { + text-transform: uppercase; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .uppercase { - text-transform: uppercase; - } - .align-banana, - .hover\:align-banana:hover { - text-align: banana; - } - .focus\:hover\:align-chocolate:hover:focus { - text-align: chocolate; - } - `) - }) + .align-banana, + .hover\:align-banana:hover { + text-align: banana; + } + .focus\:hover\:align-chocolate:hover:focus { + text-align: chocolate; + } + `) }) +}) - test('comments can be used inside layers without crashing', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], +test('comments can be used inside layers without crashing', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer base { + /* Important base */ + div { + background-color: #bada55; + } } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer base { - /* Important base */ - div { - background-color: #bada55; - } + @layer utilities { + /* Important utility */ + .important-utility { + text-align: banana; } + } - @layer utilities { - /* Important utility */ + @layer components { + /* Important component */ + .important-component { + text-align: banana; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + div { + background-color: #bada55; + } + ${defaults} + .important-component, .important-utility { - text-align: banana; - } + text-align: banana; } - - @layer components { - /* Important component */ - .important-component { - text-align: banana; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - div { - background-color: #bada55; - } - ${defaults} - .important-component, - .important-utility { - text-align: banana; - } - `) - }) + `) }) +}) - test('comments can be used inside layers (with important) without crashing', () => { - let config = { - important: true, - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], +test('comments can be used inside layers (with important) without crashing', () => { + let config = { + important: true, + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer base { + /* Important base */ + div { + background-color: #bada55; + } } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer base { - /* Important base */ - div { - background-color: #bada55; - } + @layer utilities { + /* Important utility */ + .important-utility { + text-align: banana; } + } - @layer utilities { - /* Important utility */ - .important-utility { - text-align: banana; - } + @layer components { + /* Important component */ + .important-component { + text-align: banana; } + } + ` - @layer components { - /* Important component */ - .important-component { - text-align: banana; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + div { + background-color: #bada55; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - div { - background-color: #bada55; - } - ${defaults} - .important-component { - text-align: banana; - } - .important-utility { - text-align: banana !important; - } - `) - }) + ${defaults} + .important-component { + text-align: banana; + } + .important-utility { + text-align: banana !important; + } + `) }) +}) - test('layers are grouped and inserted at the matching @tailwind rule', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addBase, addComponents, addUtilities }) { - addBase({ body: { margin: 0 } }) +test('layers are grouped and inserted at the matching @tailwind rule', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addBase, addComponents, addUtilities }) { + addBase({ body: { margin: 0 } }) - addComponents({ - '.input': { background: 'white' }, - }) + addComponents({ + '.input': { background: 'white' }, + }) - addUtilities({ - '.float-squirrel': { float: 'squirrel' }, - }) - }, - ], - corePlugins: { preflight: false }, + addUtilities({ + '.float-squirrel': { float: 'squirrel' }, + }) + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @layer vanilla { + strong { + font-weight: medium; + } } - let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + + @layer components { + .btn { + background: blue; + } + } + + @layer utilities { + .align-banana { + text-align: banana; + } + } + + @layer base { + h1 { + font-weight: bold; + } + } + + @layer components { + .card { + border-radius: 12px; + } + } + + @layer base { + p { + font-weight: normal; + } + } + + @layer utilities { + .align-sandwich { + text-align: sandwich; + } + } + + @layer chocolate { + a { + text-decoration: underline; + } + } + ` + + expect.assertions(2) + + return run(input, config).then((result) => { + expect(result.warnings().length).toBe(0) + expect(result.css).toMatchFormattedCss(css` @layer vanilla { strong { font-weight: medium; } } - - @tailwind base; - @tailwind components; - @tailwind utilities; - - @layer components { - .btn { - background: blue; - } + body { + margin: 0; } - - @layer utilities { - .align-banana { - text-align: banana; - } + h1 { + font-weight: bold; } - - @layer base { - h1 { - font-weight: bold; - } + p { + font-weight: normal; } - - @layer components { - .card { - border-radius: 12px; - } + ${defaults} + .input { + background: #fff; } - - @layer base { - p { - font-weight: normal; - } + .btn { + background: #00f; } - - @layer utilities { - .align-sandwich { - text-align: sandwich; - } + .card { + border-radius: 12px; + } + .float-squirrel { + float: squirrel; + } + .align-banana { + text-align: banana; + } + .align-sandwich { + text-align: sandwich; } - @layer chocolate { a { text-decoration: underline; } } - ` - - expect.assertions(2) - - return run(input, config).then((result) => { - expect(result.warnings().length).toBe(0) - expect(result.css).toMatchFormattedCss(css` - @layer vanilla { - strong { - font-weight: medium; - } - } - body { - margin: 0; - } - h1 { - font-weight: bold; - } - p { - font-weight: normal; - } - ${defaults} - .input { - background: #fff; - } - .btn { - background: #00f; - } - .card { - border-radius: 12px; - } - .float-squirrel { - float: squirrel; - } - .align-banana { - text-align: banana; - } - .align-sandwich { - text-align: sandwich; - } - @layer chocolate { - a { - text-decoration: underline; - } - } - `) - }) - }) - - it('should keep `@supports` rules inside `@layer`s', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - } - - let input = css` - @tailwind utilities; - - @layer utilities { - .test { - --tw-test: 1; - } - - @supports (backdrop-filter: blur(1px)) { - .test { - --tw-test: 0.9; - } - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .test { - --tw-test: 1; - } - @supports (backdrop-filter: blur(1px)) { - .test { - --tw-test: 0.9; - } - } - `) - }) + `) + }) +}) + +it('should keep `@supports` rules inside `@layer`s', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind utilities; + + @layer utilities { + .test { + --tw-test: 1; + } + + @supports (backdrop-filter: blur(1px)) { + .test { + --tw-test: 0.9; + } + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .test { + --tw-test: 1; + } + @supports (backdrop-filter: blur(1px)) { + .test { + --tw-test: 0.9; + } + } + `) }) }) diff --git a/tests/layer-without-tailwind.test.js b/tests/layer-without-tailwind.test.js index f15d43351..4122873c9 100644 --- a/tests/layer-without-tailwind.test.js +++ b/tests/layer-without-tailwind.test.js @@ -1,81 +1,79 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('using @layer without @tailwind', async () => { - let config = { - content: [{ raw: html`
` }], - } +test('using @layer without @tailwind', async () => { + let config = { + content: [{ raw: html`
` }], + } - let input = css` - @layer components { - .foo { - color: black; - } + let input = css` + @layer components { + .foo { + color: black; } - ` - - await expect(run(input, config)).rejects.toThrowError( - '`@layer components` is used but no matching `@tailwind components` directive is present.' - ) - }) - - test('using @responsive without @tailwind', async () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` - @responsive { - .foo { - color: black; - } + await expect(run(input, config)).rejects.toThrowError( + '`@layer components` is used but no matching `@tailwind components` directive is present.' + ) +}) + +test('using @responsive without @tailwind', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @responsive { + .foo { + color: black; } - ` - - await expect(run(input, config)).rejects.toThrowError( - '`@responsive` is used but `@tailwind utilities` is missing.' - ) - }) - - test('using @variants without @tailwind', async () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` - @variants hover { - .foo { - color: black; - } + await expect(run(input, config)).rejects.toThrowError( + '`@responsive` is used but `@tailwind utilities` is missing.' + ) +}) + +test('using @variants without @tailwind', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @variants hover { + .foo { + color: black; } - ` - - await expect(run(input, config)).rejects.toThrowError( - '`@variants` is used but `@tailwind utilities` is missing.' - ) - }) - - test('non-Tailwind @layer rules are okay', async () => { - let config = { - content: [{ raw: html`
` }], } + ` - let input = css` + await expect(run(input, config)).rejects.toThrowError( + '`@variants` is used but `@tailwind utilities` is missing.' + ) +}) + +test('non-Tailwind @layer rules are okay', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @layer custom { + .foo { + color: black; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` @layer custom { .foo { - color: black; + color: #000; } } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @layer custom { - .foo { - color: #000; - } - } - `) - }) + `) }) }) diff --git a/tests/match-components.test.js b/tests/match-components.test.js index a8b546127..8f6241724 100644 --- a/tests/match-components.test.js +++ b/tests/match-components.test.js @@ -1,86 +1,82 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(() => { - it('should be possible to matchComponents', () => { - let config = { - content: [ - { - raw: html`
-
-
- -
`, - }, - ], - corePlugins: { - preflight: false, +it('should be possible to matchComponents', () => { + let config = { + content: [ + { + raw: html`
+
+
+ +
`, }, - plugins: [ - function ({ matchComponents }) { - matchComponents({ - card: (value) => { - return [ - { color: value }, - { - '.card-header': { - borderTopWidth: 3, - borderTopColor: value, - }, + ], + corePlugins: { + preflight: false, + }, + plugins: [ + function ({ matchComponents }) { + matchComponents({ + card: (value) => { + return [ + { color: value }, + { + '.card-header': { + borderTopWidth: 3, + borderTopColor: value, }, - { - '.card-footer': { - borderBottomWidth: 3, - borderBottomColor: value, - }, + }, + { + '.card-footer': { + borderBottomWidth: 3, + borderBottomColor: value, }, - ] - }, - }) - }, - ], - } + }, + ] + }, + }) + }, + ], + } - return run('@tailwind base; @tailwind components; @tailwind utilities', config).then( - (result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .card-\[\#0088cc\] { - color: #08c; - } - .card-\[\#0088cc\] .card-header { - border-top-width: 3px; - border-top-color: #08c; - } - .card-\[\#0088cc\] .card-footer { - border-bottom-width: 3px; - border-bottom-color: #08c; - } - .text-center { - text-align: center; - } - .font-bold { - font-weight: 700; - } - .shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - .hover\:card-\[\#f0f\]:hover { - color: #f0f; - } - .hover\:card-\[\#f0f\]:hover .card-header { - border-top-width: 3px; - border-top-color: #f0f; - } - .hover\:card-\[\#f0f\]:hover .card-footer { - border-bottom-width: 3px; - border-bottom-color: #f0f; - } - `) + return run('@tailwind base; @tailwind components; @tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .card-\[\#0088cc\] { + color: #08c; } - ) + .card-\[\#0088cc\] .card-header { + border-top-width: 3px; + border-top-color: #08c; + } + .card-\[\#0088cc\] .card-footer { + border-bottom-width: 3px; + border-bottom-color: #08c; + } + .text-center { + text-align: center; + } + .font-bold { + font-weight: 700; + } + .shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .hover\:card-\[\#f0f\]:hover { + color: #f0f; + } + .hover\:card-\[\#f0f\]:hover .card-header { + border-top-width: 3px; + border-top-color: #f0f; + } + .hover\:card-\[\#f0f\]:hover .card-footer { + border-bottom-width: 3px; + border-bottom-color: #f0f; + } + `) }) }) diff --git a/tests/match-utilities.test.js b/tests/match-utilities.test.js index 9b3cd4c56..41ef29a29 100644 --- a/tests/match-utilities.test.js +++ b/tests/match-utilities.test.js @@ -1,575 +1,573 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('match utilities with modifiers', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, +test('match utilities with modifiers', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, - plugins: [ - ({ matchUtilities }) => { - matchUtilities( - { - test: (value, { modifier }) => ({ - color: `${value}_${modifier}`, - }), + plugins: [ + ({ matchUtilities }) => { + matchUtilities( + { + test: (value, { modifier }) => ({ + color: `${value}_${modifier}`, + }), + }, + { + values: { + DEFAULT: 'default', + bar: 'bar', + '1': 'one', + '2': 'two', + '1/foo': 'onefoo', + '[8]/[9]': 'eightnine', }, - { - values: { - DEFAULT: 'default', - bar: 'bar', - '1': 'one', - '2': 'two', - '1/foo': 'onefoo', - '[8]/[9]': 'eightnine', - }, - modifiers: 'any', - } - ) - }, - ], + modifiers: 'any', + } + ) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .test { + color: default_null; } + .test-1\/\[foo\] { + color: one_[foo]; + } + .test-1\/foo { + color: onefoo_null; + } + .test-2\/foo { + color: two_foo; + } + .test-\[8\]\/\[9\] { + color: eightnine_null; + } + .test\/\[foo\] { + color: default_[foo]; + } + .test\/foo { + color: default_foo; + } + `) +}) - let input = css` - @tailwind utilities; - ` +test('match utilities with modifiers in the config', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, - let result = await run(input, config) + plugins: [ + ({ matchUtilities }) => { + matchUtilities( + { + test: (value, { modifier }) => ({ + color: `${value}_${modifier}`, + }), + }, + { + values: { + DEFAULT: 'default', + bar: 'bar', + '1': 'one', + }, + modifiers: { + foo: 'mewtwo', + }, + } + ) + }, + ], + } - expect(result.css).toMatchFormattedCss(css` - .test { - color: default_null; - } - .test-1\/\[foo\] { - color: one_[foo]; - } - .test-1\/foo { - color: onefoo_null; - } - .test-2\/foo { - color: two_foo; - } - .test-\[8\]\/\[9\] { - color: eightnine_null; - } - .test\/\[foo\] { - color: default_[foo]; - } - .test\/foo { - color: default_foo; + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .test { + color: default_null; + } + .test-1\/\[bar\] { + color: one_bar; + } + .test-1\/foo { + color: one_mewtwo; + } + .test\/\[bar\] { + color: default_bar; + } + .test\/foo { + color: default_mewtwo; + } + `) +}) + +test('match utilities can omit utilities by returning null', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + + plugins: [ + ({ matchUtilities }) => { + matchUtilities( + { + test: (value, { modifier }) => + modifier === 'bad' + ? null + : { + color: `${value}_${modifier}`, + }, + }, + { + values: { + DEFAULT: 'default', + bar: 'bar', + '1': 'one', + }, + modifiers: 'any', + } + ) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .test { + color: default_null; + } + .test\/good { + color: default_good; + } + `) +}) + +test('matching utilities with a basic configured value', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value) => ({ value }), + }, + { + values: { + foo: 'value_foo', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-foo { + value: value_foo; + } + `) + }) +}) + +test('matching utilities with an arbitrary value and configured modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + modifiers: { + bar: 'configured_bar', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-\[foo\]\/bar { + value: foo; + modifier: configured_bar; + } + `) + }) +}) + +test('matching utilities with an configured value and an arbitrary modifier (raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'configured_foo', + }, + modifiers: 'any', // Raw `[value]` + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-foo\/\[bar\] { + value: configured_foo; + modifier: [bar]; + } + `) + }) +}) + +test('matching utilities with an configured value and an arbitrary modifier (non-raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'configured_foo', + }, + modifiers: {}, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-foo\/\[bar\] { + value: configured_foo; + modifier: bar; + } + `) + }) +}) + +test('matching utilities with an configured value and a configured modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'configured_foo', + }, + modifiers: { + bar: 'configured_bar', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-foo\/bar { + value: configured_foo; + modifier: configured_bar; + } + `) + }) +}) + +test('matching utilities with an arbitrary value and an arbitrary modifier (raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + modifiers: 'any', + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-\[foo\]\/\[bar\] { + value: foo; + modifier: [bar]; + } + `) + }) +}) + +test('matching utilities with an arbitrary value and an arbitrary modifier (non-raw)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + modifiers: {}, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-\[foo\]\/\[bar\] { + value: foo; + modifier: bar; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/[bar]': 'hello', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-\[foo\]\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = any)', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/[bar]': 'hello', + }, + modifiers: 'any', + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-\[foo\]\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = {})', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/[bar]': 'hello', + }, + modifiers: {}, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-\[foo\]\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like an arbitrary value and a configured modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + '[foo]/bar': 'hello', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-\[foo\]\/bar { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that looks like a configured value and an arbitrary modifier', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + 'foo/[bar]': 'hello', + }, + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-foo\/\[bar\] { + value: hello; + } + `) + }) +}) + +test('matching utilities with a lookup value that does not match the configured type', () => { + let config = { + content: [{ raw: html`
` }], + theme: {}, + plugins: [ + function ({ matchUtilities }) { + matchUtilities( + { + test: (value, { modifier }) => ({ value, modifier }), + }, + { + values: { + foo: 'not-a-percentage', + }, + type: ['percentage'], + } + ) + }, + ], + corePlugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .test-foo { + value: not-a-percentage; } `) }) - - test('match utilities with modifiers in the config', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - - plugins: [ - ({ matchUtilities }) => { - matchUtilities( - { - test: (value, { modifier }) => ({ - color: `${value}_${modifier}`, - }), - }, - { - values: { - DEFAULT: 'default', - bar: 'bar', - '1': 'one', - }, - modifiers: { - foo: 'mewtwo', - }, - } - ) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .test { - color: default_null; - } - .test-1\/\[bar\] { - color: one_bar; - } - .test-1\/foo { - color: one_mewtwo; - } - .test\/\[bar\] { - color: default_bar; - } - .test\/foo { - color: default_mewtwo; - } - `) - }) - - test('match utilities can omit utilities by returning null', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - - plugins: [ - ({ matchUtilities }) => { - matchUtilities( - { - test: (value, { modifier }) => - modifier === 'bad' - ? null - : { - color: `${value}_${modifier}`, - }, - }, - { - values: { - DEFAULT: 'default', - bar: 'bar', - '1': 'one', - }, - modifiers: 'any', - } - ) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .test { - color: default_null; - } - .test\/good { - color: default_good; - } - `) - }) - - test('matching utilities with a basic configured value', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value) => ({ value }), - }, - { - values: { - foo: 'value_foo', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo { - value: value_foo; - } - `) - }) - }) - - test('matching utilities with an arbitrary value and configured modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - modifiers: { - bar: 'configured_bar', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/bar { - value: foo; - modifier: configured_bar; - } - `) - }) - }) - - test('matching utilities with an configured value and an arbitrary modifier (raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'configured_foo', - }, - modifiers: 'any', // Raw `[value]` - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/\[bar\] { - value: configured_foo; - modifier: [bar]; - } - `) - }) - }) - - test('matching utilities with an configured value and an arbitrary modifier (non-raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'configured_foo', - }, - modifiers: {}, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/\[bar\] { - value: configured_foo; - modifier: bar; - } - `) - }) - }) - - test('matching utilities with an configured value and a configured modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'configured_foo', - }, - modifiers: { - bar: 'configured_bar', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/bar { - value: configured_foo; - modifier: configured_bar; - } - `) - }) - }) - - test('matching utilities with an arbitrary value and an arbitrary modifier (raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - modifiers: 'any', - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: foo; - modifier: [bar]; - } - `) - }) - }) - - test('matching utilities with an arbitrary value and an arbitrary modifier (non-raw)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - modifiers: {}, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: foo; - modifier: bar; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/[bar]': 'hello', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = any)', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/[bar]': 'hello', - }, - modifiers: 'any', - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and modifier (with modifiers = {})', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/[bar]': 'hello', - }, - modifiers: {}, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like an arbitrary value and a configured modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - '[foo]/bar': 'hello', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-\[foo\]\/bar { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that looks like a configured value and an arbitrary modifier', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - 'foo/[bar]': 'hello', - }, - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo\/\[bar\] { - value: hello; - } - `) - }) - }) - - test('matching utilities with a lookup value that does not match the configured type', () => { - let config = { - content: [{ raw: html`
` }], - theme: {}, - plugins: [ - function ({ matchUtilities }) { - matchUtilities( - { - test: (value, { modifier }) => ({ value, modifier }), - }, - { - values: { - foo: 'not-a-percentage', - }, - type: ['percentage'], - } - ) - }, - ], - corePlugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .test-foo { - value: not-a-percentage; - } - `) - }) - }) }) diff --git a/tests/match-variants.test.js b/tests/match-variants.test.js index e4330f7a9..2923b10c0 100644 --- a/tests/match-variants.test.js +++ b/tests/match-variants.test.js @@ -1,856 +1,820 @@ import resolveConfig from '../src/public/resolve-config' import { createContext } from '../src/lib/setupContextUtils' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('partial arbitrary variants', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('potato', (flavor) => `.potato-${flavor} &`) - }, - ], - } +test('partial arbitrary variants', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('potato', (flavor) => `.potato-${flavor} &`) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .potato-baked .potato-\[baked\]\:w-3 { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .potato-baked .potato-\[baked\]\:w-3 { + width: 0.75rem; + } + .potato-yellow .potato-\[yellow\]\:bg-yellow-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 240 138 / var(--tw-bg-opacity)); + } + `) + }) +}) + +test('partial arbitrary variants with at-rules', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('potato', (flavor) => `@media (potato: ${flavor})`) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (potato: baked) { + .potato-\[baked\]\:w-3 { width: 0.75rem; } - .potato-yellow .potato-\[yellow\]\:bg-yellow-200 { + } + @media (potato: yellow) { + .potato-\[yellow\]\:bg-yellow-200 { --tw-bg-opacity: 1; background-color: rgb(254 240 138 / var(--tw-bg-opacity)); } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .potato-baked .potato-\[baked\]\:w-3 { + } + `) + }) +}) + +test('partial arbitrary variants with at-rules and placeholder', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('potato', (flavor) => `@media (potato: ${flavor}) { &:potato }`) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (potato: baked) { + .potato-\[baked\]\:w-3:potato { width: 0.75rem; } - .potato-yellow .potato-\[yellow\]\:bg-yellow-200 { - background-color: #fef08a; + } + @media (potato: yellow) { + .potato-\[yellow\]\:bg-yellow-200:potato { + --tw-bg-opacity: 1; + background-color: rgb(254 240 138 / var(--tw-bg-opacity)); } - `) - }) + } + `) }) +}) - test('partial arbitrary variants with at-rules', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('potato', (flavor) => `@media (potato: ${flavor})`) - }, - ], - } +test('partial arbitrary variants with default values', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('tooltip', (side) => `&${side}`, { + values: { + bottom: '[data-location="bottom"]', + top: '[data-location="top"]', + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3 { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 240 138 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3 { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200 { - background-color: #fef08a; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tooltip-bottom\:mt-2[data-location='bottom'] { + margin-top: 0.5rem; + } + .tooltip-top\:mb-2[data-location='top'] { + margin-bottom: 0.5rem; + } + `) }) +}) - test('partial arbitrary variants with at-rules and placeholder', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('potato', (flavor) => `@media (potato: ${flavor}) { &:potato }`) - }, - ], - } +test('matched variant values maintain the sort order they are registered in', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('alphabet', (side) => `&${side}`, { + values: { + a: '[data-value="a"]', + b: '[data-value="b"]', + c: '[data-value="c"]', + d: '[data-value="d"]', + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3:potato { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200:potato { - --tw-bg-opacity: 1; - background-color: rgb(254 240 138 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (potato: baked) { - .potato-\[baked\]\:w-3:potato { - width: 0.75rem; - } - } - @media (potato: yellow) { - .potato-\[yellow\]\:bg-yellow-200:potato { - background-color: #fef08a; - } - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .alphabet-a\:underline[data-value='a'], + .alphabet-b\:underline[data-value='b'], + .alphabet-c\:underline[data-value='c'], + .alphabet-d\:underline[data-value='d'] { + text-decoration-line: underline; + } + `) }) +}) - test('partial arbitrary variants with default values', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('tooltip', (side) => `&${side}`, { - values: { - bottom: '[data-location="bottom"]', - top: '[data-location="top"]', - }, - }) - }, - ], - } +test('matchVariant can return an array of format strings from the function', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('test', (selector) => + selector.split(',').map((selector) => `&.${selector} > *`) + ) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .tooltip-bottom\:mt-2[data-location='bottom'] { - margin-top: 0.5rem; - } - .tooltip-top\:mb-2[data-location='top'] { - margin-bottom: 0.5rem; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .test-\[a\,b\,c\]\:underline.a > *, + .test-\[a\,b\,c\]\:underline.b > *, + .test-\[a\,b\,c\]\:underline.c > * { + text-decoration-line: underline; + } + `) }) +}) - test('matched variant values maintain the sort order they are registered in', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('alphabet', (side) => `&${side}`, { - values: { - a: '[data-value="a"]', - b: '[data-value="b"]', - c: '[data-value="c"]', - d: '[data-value="d"]', - }, - }) - }, - ], - } +it('should be possible to sort variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .alphabet-a\:underline[data-value='a'], - .alphabet-b\:underline[data-value='b'], - .alphabet-c\:underline[data-value='c'], - .alphabet-d\:underline[data-value='d'] { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 500px) { + .testmin-\[500px\]\:underline { text-decoration-line: underline; } - `) - }) - }) - - test('matchVariant can return an array of format strings from the function', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('test', (selector) => - selector.split(',').map((selector) => `&.${selector} > *`) - ) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .test-\[a\,b\,c\]\:underline.a > *, - .test-\[a\,b\,c\]\:underline.b > *, - .test-\[a\,b\,c\]\:underline.c > * { - text-decoration-line: underline; + } + @media (min-width: 700px) { + .testmin-\[700px\]\:italic { + font-style: italic; } - `) - }) + } + `) }) +}) - it('should be possible to sort variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - }, - ], - } +it('should be possible to compare arbitrary variants and hardcoded variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + values: { + example: '600px', + }, + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + }, + ], + } - let input = css` - @tailwind utilities; - ` + let input = css` + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { - .testmin-\[500px\]\:underline { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 500px) { + .testmin-\[500px\]\:italic { + font-style: italic; + } + } + @media (min-width: 600px) { + .testmin-example\:italic { + font-style: italic; + } + } + @media (min-width: 700px) { + .testmin-\[700px\]\:italic { + font-style: italic; + } + } + `) + }) +}) + +it('should be possible to sort stacked arbitrary variants correctly', () => { + let config = { + content: [ + { + raw: html` +
+ +
+ +
+ +
+ +
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 400px) { + .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (min-width: 700px) { - .testmin-\[700px\]\:italic { - font-style: italic; + @media (max-width: 350px) { + .testmin-\[100px\]\:testmax-\[350px\]\:underline { + text-decoration-line: underline; } } - `) - }) + @media (max-width: 300px) { + .testmin-\[100px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; + } + } + } + @media (min-width: 150px) { + @media (max-width: 400px) { + .testmin-\[150px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; + } + } + } + `) }) +}) - it('should be possible to compare arbitrary variants and hardcoded variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - values: { - example: '600px', - }, - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - }, - ], - } +it('should maintain sort from other variants, if sort functions of arbitrary variants return 0', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) - let input = css` - @tailwind utilities; - ` + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { - .testmin-\[500px\]\:italic { - font-style: italic; + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 200px) { + .testmin-\[100px\]\:testmax-\[200px\]\:hover\:underline:hover, + .testmin-\[100px\]\:testmax-\[200px\]\:focus\:underline:focus { + text-decoration-line: underline; } } - @media (min-width: 600px) { - .testmin-example\:italic { - font-style: italic; - } - } - @media (min-width: 700px) { - .testmin-\[700px\]\:italic { - font-style: italic; - } - } - `) - }) + } + `) }) +}) - it('should be possible to sort stacked arbitrary variants correctly', () => { - let config = { - content: [ - { - raw: html` -
- -
- -
- -
- -
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) +it('should sort arbitrary variants left to right (1)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } + let input = css` + @tailwind utilities; + ` - let input = css` - @tailwind utilities; - ` + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 400px) { + .testmin-\[100px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; + } + } + @media (max-width: 300px) { + .testmin-\[100px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; + } + } + } + @media (min-width: 200px) { + @media (max-width: 400px) { + .testmin-\[200px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; + } + } + @media (max-width: 300px) { + .testmin-\[200px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; + } + } + } + `) + }) +}) - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` +it('should sort arbitrary variants left to right (2)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + return parseInt(a.value) - parseInt(z.value) + }, + }) + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + return parseInt(z.value) - parseInt(a.value) + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (max-width: 400px) { @media (min-width: 100px) { - @media (max-width: 400px) { - .testmin-\[100px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 350px) { - .testmin-\[100px\]\:testmax-\[350px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 300px) { - .testmin-\[100px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } - } - } - @media (min-width: 150px) { - @media (max-width: 400px) { - .testmin-\[150px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - it('should maintain sort from other variants, if sort functions of arbitrary variants return 0', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 200px) { - .testmin-\[100px\]\:testmax-\[200px\]\:hover\:underline:hover, - .testmin-\[100px\]\:testmax-\[200px\]\:focus\:underline:focus { - text-decoration-line: underline; - } - } - } - `) - }) - }) - - it('should sort arbitrary variants left to right (1)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 400px) { - .testmin-\[100px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 300px) { - .testmin-\[100px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + .testmax-\[400px\]\:testmin-\[100px\]\:underline { + text-decoration-line: underline; } } @media (min-width: 200px) { - @media (max-width: 400px) { - .testmin-\[200px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - @media (max-width: 300px) { - .testmin-\[200px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + .testmax-\[400px\]\:testmin-\[200px\]\:underline { + text-decoration-line: underline; } } - `) - }) - }) + } - it('should sort arbitrary variants left to right (2)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - return parseInt(a.value) - parseInt(z.value) - }, - }) - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - return parseInt(z.value) - parseInt(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (max-width: 400px) { - @media (min-width: 100px) { - .testmax-\[400px\]\:testmin-\[100px\]\:underline { - text-decoration-line: underline; - } + @media (max-width: 300px) { + @media (min-width: 100px) { + .testmax-\[300px\]\:testmin-\[100px\]\:underline { + text-decoration-line: underline; } - @media (min-width: 200px) { - .testmax-\[400px\]\:testmin-\[200px\]\:underline { - text-decoration-line: underline; + } + @media (min-width: 200px) { + .testmax-\[300px\]\:testmin-\[200px\]\:underline { + text-decoration-line: underline; + } + } + } + `) + }) +}) + +it('should guarantee that we are not passing values from other variants to the wrong function', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('testmin', (value) => `@media (min-width: ${value})`, { + sort(a, z) { + let lookup = ['100px', '200px'] + if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { + throw new Error('We are seeing values that should not be there!') } + return lookup.indexOf(a.value) - lookup.indexOf(z.value) + }, + }) + matchVariant('testmax', (value) => `@media (max-width: ${value})`, { + sort(a, z) { + let lookup = ['300px', '400px'] + if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { + throw new Error('We are seeing values that should not be there!') + } + return lookup.indexOf(z.value) - lookup.indexOf(a.value) + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 100px) { + @media (max-width: 400px) { + .testmin-\[100px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; } } @media (max-width: 300px) { - @media (min-width: 100px) { - .testmax-\[300px\]\:testmin-\[100px\]\:underline { - text-decoration-line: underline; - } - } - @media (min-width: 200px) { - .testmax-\[300px\]\:testmin-\[200px\]\:underline { - text-decoration-line: underline; - } + .testmin-\[100px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; } } - `) - }) - }) + } - it('should guarantee that we are not passing values from other variants to the wrong function', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('testmin', (value) => `@media (min-width: ${value})`, { - sort(a, z) { - let lookup = ['100px', '200px'] - if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { - throw new Error('We are seeing values that should not be there!') - } - return lookup.indexOf(a.value) - lookup.indexOf(z.value) - }, - }) - matchVariant('testmax', (value) => `@media (max-width: ${value})`, { - sort(a, z) { - let lookup = ['300px', '400px'] - if (lookup.indexOf(a.value) === -1 || lookup.indexOf(z.value) === -1) { - throw new Error('We are seeing values that should not be there!') - } - return lookup.indexOf(z.value) - lookup.indexOf(a.value) - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 400px) { - .testmin-\[100px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - - @media (max-width: 300px) { - .testmin-\[100px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + @media (min-width: 200px) { + @media (max-width: 400px) { + .testmin-\[200px\]\:testmax-\[400px\]\:underline { + text-decoration-line: underline; } } - @media (min-width: 200px) { - @media (max-width: 400px) { - .testmin-\[200px\]\:testmax-\[400px\]\:underline { - text-decoration-line: underline; - } - } - - @media (max-width: 300px) { - .testmin-\[200px\]\:testmax-\[300px\]\:underline { - text-decoration-line: underline; - } + @media (max-width: 300px) { + .testmin-\[200px\]\:testmax-\[300px\]\:underline { + text-decoration-line: underline; } } - `) - }) - }) - - it('should default to the DEFAULT value for variants', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value} &`, { - values: { - DEFAULT: '.bar', - }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo.bar .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should not generate anything if the matchVariant does not have a DEFAULT value configured', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value} &`) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css``) - }) - }) - - it('should be possible to use `null` as a DEFAULT value', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value === null ? '-good' : '-bad'} &`, { - values: { DEFAULT: null }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo-good .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to use `undefined` as a DEFAULT value', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { - values: { DEFAULT: undefined }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo-good .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should be possible to use `undefined` as a DEFAULT value', () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - plugins: [ - ({ matchVariant }) => { - matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { - values: { DEFAULT: undefined }, - }) - }, - ], - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo-good .foo\:underline { - text-decoration-line: underline; - } - `) - }) - }) - - it('should not break things', () => { - let config = {} - - let context = createContext(resolveConfig(config)) - let [[, fn]] = context.variantMap.get('group') - - let format - - expect( - fn({ - format(input) { - format = input - }, - }) - ).toBe(undefined) - - expect(format).toBe(':merge(.group) &') + } + `) }) }) + +it('should default to the DEFAULT value for variants', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value} &`, { + values: { + DEFAULT: '.bar', + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo.bar .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should not generate anything if the matchVariant does not have a DEFAULT value configured', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value} &`) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css``) + }) +}) + +it('should be possible to use `null` as a DEFAULT value', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value === null ? '-good' : '-bad'} &`, { + values: { DEFAULT: null }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo-good .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to use `undefined` as a DEFAULT value', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { + values: { DEFAULT: undefined }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo-good .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should be possible to use `undefined` as a DEFAULT value', () => { + let config = { + content: [ + { + raw: html` +
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + ({ matchVariant }) => { + matchVariant('foo', (value) => `.foo${value === undefined ? '-good' : '-bad'} &`, { + values: { DEFAULT: undefined }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo-good .foo\:underline { + text-decoration-line: underline; + } + `) + }) +}) + +it('should not break things', () => { + let config = {} + + let context = createContext(resolveConfig(config)) + let [[, fn]] = context.variantMap.get('group') + + let format + + expect( + fn({ + format(input) { + format = input + }, + }) + ).toBe(undefined) + + expect(format).toBe(':merge(.group) &') +}) diff --git a/tests/min-max-screen-variants.test.js b/tests/min-max-screen-variants.test.js index a86c6f6cd..beab47ac0 100644 --- a/tests/min-max-screen-variants.test.js +++ b/tests/min-max-screen-variants.test.js @@ -1,656 +1,642 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - let defaultScreens = { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', +let defaultScreens = { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', +} + +it('sorts min and max correctly relative to screens and each other', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: defaultScreens, + }, } - it('sorts min and max correctly relative to screens and each other', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: defaultScreens, - }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (max-width: 800px) { - .max-\[800px\]\:font-bold { - font-weight: 700; - } - } - @media (max-width: 700px) { - .max-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 700px) { - .min-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - @media (min-width: 800px) { - .min-\[800px\]\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('works when using min variants screens config is empty and variants all use the same unit', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) + let input = css` + @tailwind utilities; + ` + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .font-bold { font-weight: 700; } + @media (max-width: 800px) { + .max-\[800px\]\:font-bold { + font-weight: 700; + } + } + @media (max-width: 700px) { + .max-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } @media (min-width: 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } @media (min-width: 800px) { .min-\[800px\]\:font-bold { font-weight: 700; } } `) - - expect().not.toHaveBeenWarned() }) +}) - it('works when using max variants screens config is empty and variants all use the same unit', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, +it('works when using min variants screens config is empty and variants all use the same unit', async () => { + let config = { + content: [ + { + raw: html` +
+ `, }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; } + @media (min-width: 700px) { + .min-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 800px) { + .min-\[800px\]\:font-bold { + font-weight: 700; + } + } + `) - let input = css` - @tailwind utilities; - ` + expect().not.toHaveBeenWarned() +}) - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (max-width: 800px) { - .max-\[800px\]\:font-bold { - font-weight: 700; - } - } - @media (max-width: 700px) { - .max-\[700px\]\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('converts simple min-width screens for max variant', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: defaultScreens, +it('works when using max variants screens config is empty and variants all use the same unit', () => { + let config = { + content: [ + { + raw: html` +
+ `, }, - } + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media not all and (min-width: 1024px) { - .max-lg\:font-bold { - font-weight: 700; - } - } - @media (max-width: 700px) { - .max-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media not all and (min-width: 640px) { - .max-sm\:font-bold { - font-weight: 700; - } - } - @media (max-width: 300px) { - .max-\[300px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('does not have keyed screens for min variant', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: defaultScreens, - }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 300px) { - .min-\[300px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 700px) { - .min-\[700px\]\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - }) - }) - - it('warns when using min variants with complex screen configs', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - - // Any presence of an object makes it complex - yodawg: { min: '700px' }, - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) + let input = css` + @tailwind utilities; + ` + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .font-bold { font-weight: 700; } - @media (min-width: 640px) { - .sm\:font-bold { + @media (max-width: 800px) { + .max-\[800px\]\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['complex-screen-config']) - }) - - it('warns when using min variants with simple configs containing mixed units', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '48rem', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 48rem) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['mixed-screen-units']) - }) - - it('warns when using min variants with mixed units (with screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) - }) - - it('warns when using min variants with mixed units (with no screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 700px) { - .min-\[700px\]\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) - }) - - it('warns when using max variants with complex screen configs', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - - // Any presence of an object makes it complex - yodawg: { min: '700px' }, - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['complex-screen-config']) - }) - - it('warns when using max variants with simple configs containing mixed units', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '48rem', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 48rem) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['mixed-screen-units']) - }) - - it('warns when using max variants with mixed units (with screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: { - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - @media (min-width: 640px) { - .sm\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) - }) - - it('warns when using max variants with mixed units (with no screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, - }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } @media (max-width: 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } } `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) }) +}) - it('warns when using min and max variants with mixed units (with no screens config)', async () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - screens: {}, +it('converts simple min-width screens for max variant', () => { + let config = { + content: [ + { + raw: html` +
+ `, }, - } + ], + corePlugins: { preflight: false }, + theme: { + screens: defaultScreens, + }, + } - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) + let input = css` + @tailwind utilities; + ` + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .font-bold { font-weight: 700; } - @media (max-width: 700rem) { - .max-\[700rem\]\:font-bold { + @media not all and (min-width: 1024px) { + .max-lg\:font-bold { + font-weight: 700; + } + } + @media (max-width: 700px) { + .max-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media not all and (min-width: 640px) { + .max-sm\:font-bold { + font-weight: 700; + } + } + @media (max-width: 300px) { + .max-\[300px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { font-weight: 700; } } `) - - expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) }) }) + +it('does not have keyed screens for min variant', () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: defaultScreens, + }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 300px) { + .min-\[300px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 700px) { + .min-\[700px\]\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + }) +}) + +it('warns when using min variants with complex screen configs', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + + // Any presence of an object makes it complex + yodawg: { min: '700px' }, + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['complex-screen-config']) +}) + +it('warns when using min variants with simple configs containing mixed units', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '48rem', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 48rem) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['mixed-screen-units']) +}) + +it('warns when using min variants with mixed units (with screens config)', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using min variants with mixed units (with no screens config)', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 700px) { + .min-\[700px\]\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using max variants with complex screen configs', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + + // Any presence of an object makes it complex + yodawg: { min: '700px' }, + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['complex-screen-config']) +}) + +it('warns when using max variants with simple configs containing mixed units', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '48rem', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 48rem) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['mixed-screen-units']) +}) + +it('warns when using max variants with mixed units (with screens config)', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (min-width: 640px) { + .sm\:font-bold { + font-weight: 700; + } + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using max variants with mixed units (with no screens config)', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (max-width: 700px) { + .max-\[700px\]\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) + +it('warns when using min and max variants with mixed units (with no screens config)', async () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: { + screens: {}, + }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + @media (max-width: 700rem) { + .max-\[700rem\]\:font-bold { + font-weight: 700; + } + } + `) + + expect().toHaveBeenWarnedWith(['minmax-have-mixed-units']) +}) diff --git a/tests/minimum-impact-selector.test.js b/tests/minimum-impact-selector.test.js index ed2fad914..d8292e467 100644 --- a/tests/minimum-impact-selector.test.js +++ b/tests/minimum-impact-selector.test.js @@ -1,32 +1,29 @@ import { elementSelectorParser } from '../src/lib/resolveDefaultsAtRules' -import { crosscheck } from './util/run' -crosscheck(() => { - it.each` - before | after - ${'*'} | ${'*'} - ${'*:hover'} | ${'*'} - ${'* > *'} | ${'* > *'} - ${'.foo'} | ${'.foo'} - ${'.foo:hover'} | ${'.foo'} - ${'.foo:focus:hover'} | ${'.foo'} - ${'li:first-child'} | ${'li'} - ${'li:before'} | ${'li:before'} - ${'li::before'} | ${'li::before'} - ${'#app .foo'} | ${'.foo'} - ${'#app'} | ${'[id=app]'} - ${'#app.other'} | ${'.other'} - ${'input[type="text"]'} | ${'[type="text"]'} - ${'input[type="text"].foo'} | ${'.foo'} - ${'.group .group\\:foo'} | ${'.group\\:foo'} - ${'.group:hover .group-hover\\:foo'} | ${'.group-hover\\:foo'} - ${'.owl > * + *'} | ${'.owl > *'} - ${'.owl > :not([hidden]) + :not([hidden])'} | ${'.owl > *'} - ${'.group:hover .group-hover\\:owl > :not([hidden]) + :not([hidden])'} | ${'.group-hover\\:owl > *'} - ${'.peer:first-child ~ .peer-first\\:shadow-md'} | ${'.peer-first\\:shadow-md'} - ${'.whats ~ .next > span:hover'} | ${'span'} - ${'.foo .bar ~ .baz > .next > span > article:hover'} | ${'article'} - `('should generate "$after" from "$before"', ({ before, after }) => { - expect(elementSelectorParser.transformSync(before).join(', ')).toEqual(after) - }) +it.each` + before | after + ${'*'} | ${'*'} + ${'*:hover'} | ${'*'} + ${'* > *'} | ${'* > *'} + ${'.foo'} | ${'.foo'} + ${'.foo:hover'} | ${'.foo'} + ${'.foo:focus:hover'} | ${'.foo'} + ${'li:first-child'} | ${'li'} + ${'li:before'} | ${'li:before'} + ${'li::before'} | ${'li::before'} + ${'#app .foo'} | ${'.foo'} + ${'#app'} | ${'[id=app]'} + ${'#app.other'} | ${'.other'} + ${'input[type="text"]'} | ${'[type="text"]'} + ${'input[type="text"].foo'} | ${'.foo'} + ${'.group .group\\:foo'} | ${'.group\\:foo'} + ${'.group:hover .group-hover\\:foo'} | ${'.group-hover\\:foo'} + ${'.owl > * + *'} | ${'.owl > *'} + ${'.owl > :not([hidden]) + :not([hidden])'} | ${'.owl > *'} + ${'.group:hover .group-hover\\:owl > :not([hidden]) + :not([hidden])'} | ${'.group-hover\\:owl > *'} + ${'.peer:first-child ~ .peer-first\\:shadow-md'} | ${'.peer-first\\:shadow-md'} + ${'.whats ~ .next > span:hover'} | ${'span'} + ${'.foo .bar ~ .baz > .next > span > article:hover'} | ${'article'} +`('should generate "$after" from "$before"', ({ before, after }) => { + expect(elementSelectorParser.transformSync(before).join(', ')).toEqual(after) }) diff --git a/tests/modify-selectors.test.js b/tests/modify-selectors.test.js index 3176b17f3..e6ce3cf14 100644 --- a/tests/modify-selectors.test.js +++ b/tests/modify-selectors.test.js @@ -1,95 +1,93 @@ import selectorParser from 'postcss-selector-parser' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('modify selectors', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-

Lorem ipsum dolor sit amet...

-
-
-

Lorem ipsum dolor sit amet...

-
-
-

Lorem ipsum dolor sit amet...

-
-
-

Lorem ipsum dolor sit amet...

-
- `, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [ - function ({ addVariant }) { - addVariant('foo', ({ modifySelectors, separator }) => { - modifySelectors(({ selector }) => { - return selectorParser((selectors) => { - selectors.walkClasses((classNode) => { - classNode.value = `foo${separator}${classNode.value}` - classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) - }) - }).processSync(selector) - }) +test('modify selectors', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+

Lorem ipsum dolor sit amet...

+
+
+

Lorem ipsum dolor sit amet...

+
+
+

Lorem ipsum dolor sit amet...

+
+
+

Lorem ipsum dolor sit amet...

+
+ `, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [ + function ({ addVariant }) { + addVariant('foo', ({ modifySelectors, separator }) => { + modifySelectors(({ selector }) => { + return selectorParser((selectors) => { + selectors.walkClasses((classNode) => { + classNode.value = `foo${separator}${classNode.value}` + classNode.parent.insertBefore(classNode, selectorParser().astSync(`.foo `)) + }) + }).processSync(selector) }) - }, - ], + }) + }, + ], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + @layer components { + .markdown > p { + margin-top: 12px; + } } + ` - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .markdown > p { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .markdown > p { + margin-top: 12px; + } + .font-bold { + font-weight: 700; + } + .foo .foo\:markdown > p, + .foo .foo\:visited\:markdown:visited > p { + margin-top: 12px; + } + @media (min-width: 1024px) { + .foo .lg\:foo\:disabled\:markdown:disabled > p { margin-top: 12px; } } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .markdown > p { - margin-top: 12px; - } - .font-bold { + .foo .foo\:font-bold, + .foo .foo\:hover\:font-bold:hover { + font-weight: 700; + } + @media (min-width: 640px) { + .foo .sm\:foo\:font-bold { font-weight: 700; } - .foo .foo\:markdown > p, - .foo .foo\:visited\:markdown:visited > p { - margin-top: 12px; - } - @media (min-width: 1024px) { - .foo .lg\:foo\:disabled\:markdown:disabled > p { - margin-top: 12px; - } - } - .foo .foo\:font-bold, - .foo .foo\:hover\:font-bold:hover { + } + @media (min-width: 768px) { + .foo .md\:foo\:focus\:font-bold:focus { font-weight: 700; } - @media (min-width: 640px) { - .foo .sm\:foo\:font-bold { - font-weight: 700; - } - } - @media (min-width: 768px) { - .foo .md\:foo\:focus\:font-bold:focus { - font-weight: 700; - } - } - `) - }) + } + `) }) }) diff --git a/tests/mutable.test.js b/tests/mutable.test.js index 45419380f..5c3f9a487 100644 --- a/tests/mutable.test.js +++ b/tests/mutable.test.js @@ -1,54 +1,52 @@ import path from 'path' import postcss from 'postcss' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - function pluginThatMutatesRules() { - return (root) => { - root.walkRules((rule) => { - rule.nodes - .filter((node) => node.prop === 'background-image') - .forEach((node) => { - node.value = 'url("./bar.png")' - }) +function pluginThatMutatesRules() { + return (root) => { + root.walkRules((rule) => { + rule.nodes + .filter((node) => node.prop === 'background-image') + .forEach((node) => { + node.value = 'url("./bar.png")' + }) - return rule - }) - } + return rule + }) + } +} + +test('plugins mutating rules after tailwind doesnt break it', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + backgroundImage: { + foo: 'url("./foo.png")', + }, + }, + plugins: [], } - test('plugins mutating rules after tailwind doesnt break it', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - backgroundImage: { - foo: 'url("./foo.png")', - }, - }, - plugins: [], - } + function checkResult(result) { + expect(result.css).toMatchFormattedCss(css` + .bg-foo { + background-image: url('./foo.png'); + } + `) + } - function checkResult(result) { - expect(result.css).toMatchFormattedCss(css` - .bg-foo { - background-image: url('./foo.png'); - } - `) - } + // Verify the first run produces the expected result + let firstRun = await run('@tailwind utilities', config) + checkResult(firstRun) - // Verify the first run produces the expected result - let firstRun = await run('@tailwind utilities', config) - checkResult(firstRun) - - // Outside of the context of tailwind jit more postcss plugins may operate on the AST: - // In this case we have a plugin that mutates rules directly - await postcss([pluginThatMutatesRules()]).process(firstRun, { - from: path.resolve(__filename), - }) - - // Verify subsequent runs don't produce mutated rules - let secondRun = await run('@tailwind utilities', config) - checkResult(secondRun) + // Outside of the context of tailwind jit more postcss plugins may operate on the AST: + // In this case we have a plugin that mutates rules directly + await postcss([pluginThatMutatesRules()]).process(firstRun, { + from: path.resolve(__filename), }) + + // Verify subsequent runs don't produce mutated rules + let secondRun = await run('@tailwind utilities', config) + checkResult(secondRun) }) diff --git a/tests/negateValue.test.js b/tests/negateValue.test.js index 052132f91..c31741d48 100644 --- a/tests/negateValue.test.js +++ b/tests/negateValue.test.js @@ -1,17 +1,14 @@ import negateValue from '../src/util/negateValue' -import { crosscheck } from './util/run' -crosscheck(() => { - test('it negates numeric CSS values', () => { - expect(negateValue('5')).toEqual('-5') - expect(negateValue('10px')).toEqual('-10px') - expect(negateValue('18rem')).toEqual('-18rem') - expect(negateValue('-10')).toEqual('10') - expect(negateValue('-7ch')).toEqual('7ch') - }) - - test('values that cannot be negated become undefined', () => { - expect(negateValue('auto')).toBeUndefined() - expect(negateValue('cover')).toBeUndefined() - }) +test('it negates numeric CSS values', () => { + expect(negateValue('5')).toEqual('-5') + expect(negateValue('10px')).toEqual('-10px') + expect(negateValue('18rem')).toEqual('-18rem') + expect(negateValue('-10')).toEqual('10') + expect(negateValue('-7ch')).toEqual('7ch') +}) + +test('values that cannot be negated become undefined', () => { + expect(negateValue('auto')).toBeUndefined() + expect(negateValue('cover')).toBeUndefined() }) diff --git a/tests/negated-content.test.js b/tests/negated-content.test.js index 66e231946..6d46e3a8d 100644 --- a/tests/negated-content.test.js +++ b/tests/negated-content.test.js @@ -1,29 +1,27 @@ import * as path from 'path' -import { crosscheck, run, css, defaults } from './util/run' +import { run, css, defaults } from './util/run' -crosscheck(() => { - it('should be possible to use negated content patterns', () => { - let config = { - content: [ - path.resolve(__dirname, './negated-content-*.test.html'), - '!' + path.resolve(__dirname, './negated-content-ignore.test.html'), - ], - corePlugins: { preflight: false }, - } +it('should be possible to use negated content patterns', () => { + let config = { + content: [ + path.resolve(__dirname, './negated-content-*.test.html'), + '!' + path.resolve(__dirname, './negated-content-ignore.test.html'), + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .uppercase { - text-transform: uppercase; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .uppercase { + text-transform: uppercase; + } + `) }) }) diff --git a/tests/negative-prefix.test.js b/tests/negative-prefix.test.js index c799bb54e..8b4949b1a 100644 --- a/tests/negative-prefix.test.js +++ b/tests/negative-prefix.test.js @@ -1,346 +1,342 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('using a negative prefix with a negative scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 2: '8px', - '-2': '-4px', - }, +test('using a negative prefix with a negative scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 2: '8px', + '-2': '-4px', }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-2 { - margin-top: -4px; - } - .mt-2 { - margin-top: 8px; - } - `) - }) - }) - - test('using a negative scale value with a plugin that does not support dynamic negative values', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - opacity: { - '-50': '0.5', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-opacity-50 { - opacity: 0.5; - } - `) - }) - }) - - test('using a negative prefix without a negative scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 5: '20px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-5 { - margin-top: -20px; - } - .mt-5 { - margin-top: 20px; - } - `) - }) - }) - - test('being an asshole', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - '-[10px]': '55px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-\[10px\] { - margin-top: 55px; - } - `) - }) - }) - - test('being a real asshole', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - '[10px]': '55px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-\[10px\] { - margin-top: -55px; - } - `) - }) - }) - - test('a value that includes a variable', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 5: 'var(--sizing-5)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-5 { - margin-top: calc(var(--sizing-5) * -1); - } - .mt-5 { - margin-top: var(--sizing-5); - } - `) - }) - }) - - test('a value that includes a calc', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 5: 'calc(52px * -3)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-5 { - margin-top: 156px; - } - .mt-5 { - margin-top: -156px; - } - `) - }) - }) - - test('a value that includes min/max/clamp functions', () => { - let config = { - content: [ - { raw: html`
` }, - ], - theme: { - margin: { - min: 'min(100vmin, 3rem)', - max: 'max(100vmax, 3rem)', - clamp: 'clamp(1rem, 100vh, 3rem)', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-clamp { - margin-top: calc(-1 * clamp(1rem, 100vh, 3rem)); - } - .-mt-max { - margin-top: calc(-1 * max(100vmax, 3rem)); - } - .-mt-min { - margin-top: calc(-1 * min(100vmin, 3rem)); - } - .mt-clamp { - margin-top: clamp(1rem, 100vh, 3rem); - } - .mt-max { - margin-top: max(100vmax, 3rem); - } - .mt-min { - margin-top: min(100vmin, 3rem); - } - `) - }) - }) - - test('a keyword value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - auto: 'auto', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .mt-auto { - margin-top: auto; - } - `) - }) - }) - - test('a zero value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - 0: '0', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-0, - .mt-0 { - margin-top: 0; - } - `) - }) - }) - - test('a color', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - red: 'red', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css``) - }) - }) - - test('arbitrary values', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-\[10px\] { - margin-top: -10px; - } - `) - }) - }) - - test('negating a negative scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - weird: '-15px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt-weird { - margin-top: 15px; - } - `) - }) - }) - - test('negating a default value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - DEFAULT: '15px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt { - margin-top: -15px; - } - `) - }) - }) - - test('using a negative prefix with a negative default scale value', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - margin: { - DEFAULT: '8px', - '-DEFAULT': '-4px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .-mt { - margin-top: -4px; - } - .mt { - margin-top: 8px; - } - `) - }) - }) - - test('negating a default value with a configured prefix', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - theme: { - margin: { - DEFAULT: '15px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` - .tw--mt { - margin-top: -15px; - } - `) - }) - }) - - test('arbitrary value keywords should be ignored', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css``) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-2 { + margin-top: -4px; + } + .mt-2 { + margin-top: 8px; + } + `) + }) +}) + +test('using a negative scale value with a plugin that does not support dynamic negative values', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + opacity: { + '-50': '0.5', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-opacity-50 { + opacity: 0.5; + } + `) + }) +}) + +test('using a negative prefix without a negative scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 5: '20px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-5 { + margin-top: -20px; + } + .mt-5 { + margin-top: 20px; + } + `) + }) +}) + +test('being an asshole', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + '-[10px]': '55px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-\[10px\] { + margin-top: 55px; + } + `) + }) +}) + +test('being a real asshole', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + '[10px]': '55px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-\[10px\] { + margin-top: -55px; + } + `) + }) +}) + +test('a value that includes a variable', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 5: 'var(--sizing-5)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-5 { + margin-top: calc(var(--sizing-5) * -1); + } + .mt-5 { + margin-top: var(--sizing-5); + } + `) + }) +}) + +test('a value that includes a calc', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 5: 'calc(52px * -3)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-5 { + margin-top: 156px; + } + .mt-5 { + margin-top: -156px; + } + `) + }) +}) + +test('a value that includes min/max/clamp functions', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + min: 'min(100vmin, 3rem)', + max: 'max(100vmax, 3rem)', + clamp: 'clamp(1rem, 100vh, 3rem)', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-clamp { + margin-top: calc(-1 * clamp(1rem, 100vh, 3rem)); + } + .-mt-max { + margin-top: calc(-1 * max(100vmax, 3rem)); + } + .-mt-min { + margin-top: calc(-1 * min(100vmin, 3rem)); + } + .mt-clamp { + margin-top: clamp(1rem, 100vh, 3rem); + } + .mt-max { + margin-top: max(100vmax, 3rem); + } + .mt-min { + margin-top: min(100vmin, 3rem); + } + `) + }) +}) + +test('a keyword value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + auto: 'auto', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .mt-auto { + margin-top: auto; + } + `) + }) +}) + +test('a zero value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + 0: '0', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-0, + .mt-0 { + margin-top: 0; + } + `) + }) +}) + +test('a color', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + red: 'red', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css``) + }) +}) + +test('arbitrary values', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-\[10px\] { + margin-top: -10px; + } + `) + }) +}) + +test('negating a negative scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + weird: '-15px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt-weird { + margin-top: 15px; + } + `) + }) +}) + +test('negating a default value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + DEFAULT: '15px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt { + margin-top: -15px; + } + `) + }) +}) + +test('using a negative prefix with a negative default scale value', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + margin: { + DEFAULT: '8px', + '-DEFAULT': '-4px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .-mt { + margin-top: -4px; + } + .mt { + margin-top: 8px; + } + `) + }) +}) + +test('negating a default value with a configured prefix', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + theme: { + margin: { + DEFAULT: '15px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css` + .tw--mt { + margin-top: -15px; + } + `) + }) +}) + +test('arbitrary value keywords should be ignored', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchCss(css``) }) }) diff --git a/tests/normalize-config.test.js b/tests/normalize-config.test.js index 47980cbdd..0468c8c78 100644 --- a/tests/normalize-config.test.js +++ b/tests/normalize-config.test.js @@ -1,164 +1,155 @@ import { normalizeConfig } from '../src/util/normalizeConfig' import resolveConfig from '../src/public/resolve-config' -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it.each` - config - ${{ purge: [{ raw: 'text-center' }] }} - ${{ purge: { content: [{ raw: 'text-center' }] } }} - ${{ content: { files: [], content: [{ raw: 'text-center' }] } }} - `('should normalize content $config', ({ config }) => { - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-center { - text-align: center; - } - `) - }) - }) - - it.each` - config - ${{ purge: { safelist: ['text-center'] } }} - ${{ purge: { options: { safelist: ['text-center'] } } }} - ${{ content: { files: [], safelist: ['text-center'] } }} - `('should normalize safelist $config', ({ config }) => { - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-center { - text-align: center; - } - `) - }) - }) - - oxide.test.todo('should normalize extractors') - stable.test.each` - config - ${{ content: [{ raw: 'text-center' }], purge: { extract: () => ['font-bold'] } }} - ${{ content: [{ raw: 'text-center' }], purge: { extract: { DEFAULT: () => ['font-bold'] } } }} - ${{ - content: [{ raw: 'text-center' }], - purge: { options: { defaultExtractor: () => ['font-bold'] } }, - }} - ${{ - content: [{ raw: 'text-center' }], - purge: { - options: { extractors: [{ extractor: () => ['font-bold'], extensions: ['html'] }] }, - }, - }} - ${{ content: [{ raw: 'text-center' }], purge: { extract: { html: () => ['font-bold'] } } }} - `('should normalize extractors $config', ({ config }) => { - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .font-bold { - font-weight: 700; - } - `) - }) - }) - - oxide.test.todo('should still be possible to use the "old" v2 config') - stable.test('should still be possible to use the "old" v2 config', () => { - let config = { - purge: { - content: [ - { raw: 'text-svelte', extension: 'svelte' }, - { raw: '# My Big Heading', extension: 'md' }, - ], - options: { - defaultExtractor(content) { - return content.split(' ').concat(['font-bold']) - }, - }, - extract: { - svelte(content) { - return content.replace('svelte', 'center').split(' ') - }, - }, - transform: { - md() { - return 'text-4xl' - }, - }, - }, - theme: { - extends: {}, - }, - variants: { - extends: {}, - }, - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .text-center { - text-align: center; - } - .text-4xl { - font-size: 2.25rem; - line-height: 2.5rem; - } - .font-bold { - font-weight: 700; - } - `) - }) - }) - - it('should keep content files with globs', () => { - let config = { - content: ['./example-folder/**/*.{html,js}'], - } - - stable.expect(normalizeConfig(resolveConfig(config)).content).toEqual({ - files: ['./example-folder/**/*.{html,js}'], - relative: false, - extract: {}, - transform: {}, - }) - oxide.expect(normalizeConfig(resolveConfig(config)).content).toEqual({ - files: ['./example-folder/**/*.{html,js}'], - relative: true, - extract: {}, - transform: {}, - }) - }) - - it('should warn when we detect invalid globs with incorrect brace expansion', () => { - let config = { - content: [ - './{example-folder}/**/*.{html,js}', - './{example-folder}/**/*.{html}', - './example-folder/**/*.{html}', - ], - } - - let normalizedConfig = normalizeConfig(resolveConfig(config)).content - - // No rewrite happens - stable.expect(normalizedConfig).toEqual({ - files: [ - './{example-folder}/**/*.{html,js}', - './{example-folder}/**/*.{html}', - './example-folder/**/*.{html}', - ], - relative: false, - extract: {}, - transform: {}, - }) - oxide.expect(normalizedConfig).toEqual({ - files: [ - './{example-folder}/**/*.{html,js}', - './{example-folder}/**/*.{html}', - './example-folder/**/*.{html}', - ], - relative: true, - extract: {}, - transform: {}, - }) - - expect().toHaveBeenWarnedWith(['invalid-glob-braces']) +it.each` + config + ${{ purge: [{ raw: 'text-center' }] }} + ${{ purge: { content: [{ raw: 'text-center' }] } }} + ${{ content: { files: [], content: [{ raw: 'text-center' }] } }} +`('should normalize content $config', ({ config }) => { + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-center { + text-align: center; + } + `) }) }) + +it.each` + config + ${{ purge: { safelist: ['text-center'] } }} + ${{ purge: { options: { safelist: ['text-center'] } } }} + ${{ content: { files: [], safelist: ['text-center'] } }} +`('should normalize safelist $config', ({ config }) => { + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-center { + text-align: center; + } + `) + }) +}) + +test.each` + config + ${{ + purge: { content: [{ raw: 'text-center' }], extract: () => ['font-bold'] }, +}} + ${{ + purge: { content: [{ raw: 'text-center' }], extract: { DEFAULT: () => ['font-bold'] } }, +}} + ${{ + purge: { + content: [{ raw: 'text-center' }], + options: { defaultExtractor: () => ['font-bold'] }, + }, +}} + ${{ + purge: { + content: [{ raw: 'text-center' }], + options: { extractors: [{ extractor: () => ['font-bold'], extensions: ['html'] }] }, + }, +}} + ${{ + purge: { + content: [{ raw: 'text-center' }], + extract: { html: () => ['font-bold'] }, + }, +}} +`('should normalize extractors $config', ({ config }) => { + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .font-bold { + font-weight: 700; + } + `) + }) +}) + +test('should still be possible to use the "old" v2 config', () => { + let config = { + purge: { + content: [ + { raw: 'text-svelte', extension: 'svelte' }, + { raw: '# My Big Heading', extension: 'md' }, + ], + options: { + defaultExtractor(content) { + return content.split(' ').concat(['font-bold']) + }, + }, + extract: { + svelte(content) { + return content.replace('svelte', 'center').split(' ') + }, + }, + transform: { + md() { + return 'text-4xl' + }, + }, + }, + theme: { + extends: {}, + }, + variants: { + extends: {}, + }, + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .text-center { + text-align: center; + } + .text-4xl { + font-size: 2.25rem; + line-height: 2.5rem; + } + .font-bold { + font-weight: 700; + } + `) + }) +}) + +it('should keep content files with globs', () => { + let config = { + content: ['./example-folder/**/*.{html,js}'], + } + + expect(normalizeConfig(resolveConfig(config)).content).toEqual({ + files: ['./example-folder/**/*.{html,js}'], + relative: false, + extract: {}, + transform: {}, + }) +}) + +it('should warn when we detect invalid globs with incorrect brace expansion', () => { + let config = { + content: [ + './{example-folder}/**/*.{html,js}', + './{example-folder}/**/*.{html}', + './example-folder/**/*.{html}', + ], + } + + let normalizedConfig = normalizeConfig(resolveConfig(config)).content + + // No rewrite happens + expect(normalizedConfig).toEqual({ + files: [ + './{example-folder}/**/*.{html,js}', + './{example-folder}/**/*.{html}', + './example-folder/**/*.{html}', + ], + relative: false, + extract: {}, + transform: {}, + }) + + expect().toHaveBeenWarnedWith(['invalid-glob-braces']) +}) diff --git a/tests/normalize-data-types.test.js b/tests/normalize-data-types.test.js index eff2fa677..d99ce1c18 100644 --- a/tests/normalize-data-types.test.js +++ b/tests/normalize-data-types.test.js @@ -1,5 +1,4 @@ import { normalize } from '../src/util/dataTypes' -import { crosscheck } from './util/run' let table = [ ['foo', 'foo'], @@ -47,8 +46,6 @@ let table = [ ['color(0_0_0_/_1.0)', 'color(0 0 0 / 1.0)'], ] -crosscheck(() => { - it.each(table)('normalize data: %s', (input, output) => { - expect(normalize(input)).toBe(output) - }) +it.each(table)('normalize data: %s', (input, output) => { + expect(normalize(input)).toBe(output) }) diff --git a/tests/normalize-screens.test.js b/tests/normalize-screens.test.js index 464623f9f..da31c50d3 100644 --- a/tests/normalize-screens.test.js +++ b/tests/normalize-screens.test.js @@ -1,66 +1,63 @@ import { normalizeScreens } from '../src/util/normalizeScreens' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should normalize an array of string values', () => { - let screens = ['768px', '1200px'] +it('should normalize an array of string values', () => { + let screens = ['768px', '1200px'] - expect(normalizeScreens(screens)).toEqual([ - { name: '768px', not: false, values: [{ min: '768px', max: undefined }] }, - { name: '1200px', not: false, values: [{ min: '1200px', max: undefined }] }, - ]) - }) - - it('should normalize an object with string values', () => { - let screens = { - a: '768px', - b: '1200px', - } - - expect(normalizeScreens(screens)).toEqual([ - { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, - { name: 'b', not: false, values: [{ min: '1200px', max: undefined }] }, - ]) - }) - - it('should normalize an object with object values', () => { - let screens = { - a: { min: '768px' }, - b: { max: '1200px' }, - } - - expect(normalizeScreens(screens)).toEqual([ - { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, - { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, - ]) - }) - - it('should normalize an object with multiple object values', () => { - let screens = { - a: [{ min: '768px' }, { max: '1200px' }], - } - - expect(normalizeScreens(screens)).toEqual([ - { - name: 'a', - not: false, - values: [ - { max: undefined, min: '768px', raw: undefined }, - { max: '1200px', min: undefined, raw: undefined }, - ], - }, - ]) - }) - - it('should normalize an object with object values (min-width normalized to width)', () => { - let screens = { - a: { 'min-width': '768px' }, - b: { max: '1200px' }, - } - - expect(normalizeScreens(screens)).toEqual([ - { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, - { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, - ]) - }) + expect(normalizeScreens(screens)).toEqual([ + { name: '768px', not: false, values: [{ min: '768px', max: undefined }] }, + { name: '1200px', not: false, values: [{ min: '1200px', max: undefined }] }, + ]) +}) + +it('should normalize an object with string values', () => { + let screens = { + a: '768px', + b: '1200px', + } + + expect(normalizeScreens(screens)).toEqual([ + { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, + { name: 'b', not: false, values: [{ min: '1200px', max: undefined }] }, + ]) +}) + +it('should normalize an object with object values', () => { + let screens = { + a: { min: '768px' }, + b: { max: '1200px' }, + } + + expect(normalizeScreens(screens)).toEqual([ + { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, + { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, + ]) +}) + +it('should normalize an object with multiple object values', () => { + let screens = { + a: [{ min: '768px' }, { max: '1200px' }], + } + + expect(normalizeScreens(screens)).toEqual([ + { + name: 'a', + not: false, + values: [ + { max: undefined, min: '768px', raw: undefined }, + { max: '1200px', min: undefined, raw: undefined }, + ], + }, + ]) +}) + +it('should normalize an object with object values (min-width normalized to width)', () => { + let screens = { + a: { 'min-width': '768px' }, + b: { max: '1200px' }, + } + + expect(normalizeScreens(screens)).toEqual([ + { name: 'a', not: false, values: [{ min: '768px', max: undefined }] }, + { name: 'b', not: false, values: [{ min: undefined, max: '1200px' }] }, + ]) }) diff --git a/tests/opacity.test.js b/tests/opacity.test.js index 82b437ce8..4b2b0eadf 100644 --- a/tests/opacity.test.js +++ b/tests/opacity.test.js @@ -1,1115 +1,1047 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('opacity', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
- `, - }, - ], - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, +test('opacity', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+ `, }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-black > :not([hidden]) ~ :not([hidden]), - .border-black { - border-color: #000; - } - .bg-black { - background-color: #000; - } - .text-black, - .placeholder-black::placeholder { - color: #000; - } - `) - }) - }) - - test('colors defined as functions work when opacity plugins are disabled', () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: ({ opacityValue }) => - opacityValue === undefined - ? 'rgb(var(--color-primary))' - : `rgb(var(--color-primary) / ${opacityValue})`, - }, - }, - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]), - .border-primary { - border-color: rgb(var(--color-primary)); - } - .bg-primary { - background-color: rgb(var(--color-primary)); - } - .text-primary, - .placeholder-primary::placeholder { - color: rgb(var(--color-primary)); - } - `) - }) - }) - - it('can use defining custom properties for colors (opacity plugins enabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(var(--color-primary) / var(--tw-divide-opacity)); - } - .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 0.5; - } - .border-primary { - --tw-border-opacity: 1; - border-color: rgb(var(--color-primary) / var(--tw-border-opacity)); - } - .border-opacity-50 { - --tw-border-opacity: 0.5; - } - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .text-primary { - --tw-text-opacity: 1; - color: rgb(var(--color-primary) / var(--tw-text-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - .placeholder-primary::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(var(--color-primary) / var(--tw-placeholder-opacity)); - } - .placeholder-opacity-50::placeholder { - --tw-placeholder-opacity: 0.5; - } - .ring-primary { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(var(--color-primary) / var(--tw-ring-opacity)); - } - .ring-opacity-50 { - --tw-ring-opacity: 0.5; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]), - .border-primary { - border-color: rgb(var(--color-primary) / 1); - } - .bg-primary { - background-color: rgb(var(--color-primary) / 1); - } - .text-primary, - .placeholder-primary::placeholder { - color: rgb(var(--color-primary) / 1); - } - .ring-primary { - --tw-ring-color: rgb(var(--color-primary) / 1); - } - `) - }) - }) - - it('can use rgb helper when defining custom properties for colors (opacity plugins disabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, - ringOpacity: false, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(var(--color-primary) / 1); - } - .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(var(--color-primary) / 0.5); - } - .border-primary { - border-color: rgb(var(--color-primary) / 1); - } - .border-primary\/50 { - border-color: rgb(var(--color-primary) / 0.5); - } - .bg-primary { - background-color: rgb(var(--color-primary) / 1); - } - .bg-primary\/50 { - background-color: rgb(var(--color-primary) / 0.5); - } - .text-primary { - color: rgb(var(--color-primary) / 1); - } - .text-primary\/50 { - color: rgb(var(--color-primary) / 0.5); - } - .placeholder-primary::placeholder { - color: rgb(var(--color-primary) / 1); - } - .placeholder-primary\/50::placeholder { - color: rgb(var(--color-primary) / 0.5); - } - .ring-primary { - --tw-ring-color: rgb(var(--color-primary) / 1); - } - .ring-primary\/50 { - --tw-ring-color: rgb(var(--color-primary) / 0.5); - } - `) - }) - }) - - it('can use hsl helper when defining custom properties for colors (opacity plugins enabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'hsl(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: hsl(var(--color-primary) / var(--tw-divide-opacity)); - } - .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 0.5; - } - .border-primary { - --tw-border-opacity: 1; - border-color: hsl(var(--color-primary) / var(--tw-border-opacity)); - } - .border-opacity-50 { - --tw-border-opacity: 0.5; - } - .bg-primary { - --tw-bg-opacity: 1; - background-color: hsl(var(--color-primary) / var(--tw-bg-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .text-primary { - --tw-text-opacity: 1; - color: hsl(var(--color-primary) / var(--tw-text-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - .placeholder-primary::placeholder { - --tw-placeholder-opacity: 1; - color: hsl(var(--color-primary) / var(--tw-placeholder-opacity)); - } - .placeholder-opacity-50::placeholder { - --tw-placeholder-opacity: 0.5; - } - .ring-primary { - --tw-ring-opacity: 1; - --tw-ring-color: hsl(var(--color-primary) / var(--tw-ring-opacity)); - } - .ring-opacity-50 { - --tw-ring-opacity: 0.5; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]), - .border-primary { - border-color: hsl(var(--color-primary) / 1); - } - .bg-primary { - background-color: hsl(var(--color-primary) / 1); - } - .text-primary, - .placeholder-primary::placeholder { - color: hsl(var(--color-primary) / 1); - } - .ring-primary { - --tw-ring-color: hsl(var(--color-primary) / 1); - } - `) - }) - }) - - it('can use hsl helper when defining custom properties for colors (opacity plugins disabled)', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - theme: { - colors: { - primary: 'hsl(var(--color-primary) / )', - }, - }, - corePlugins: { - backgroundOpacity: false, - borderOpacity: false, - divideOpacity: false, - placeholderOpacity: false, - textOpacity: false, - ringOpacity: false, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-primary > :not([hidden]) ~ :not([hidden]) { - border-color: hsl(var(--color-primary) / 1); - } - .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: hsl(var(--color-primary) / 0.5); - } - .border-primary { - border-color: hsl(var(--color-primary) / 1); - } - .border-primary\/50 { - border-color: hsl(var(--color-primary) / 0.5); - } - .bg-primary { - background-color: hsl(var(--color-primary) / 1); - } - .bg-primary\/50 { - background-color: hsl(var(--color-primary) / 0.5); - } - .text-primary { - color: hsl(var(--color-primary) / 1); - } - .text-primary\/50 { - color: hsl(var(--color-primary) / 0.5); - } - .placeholder-primary::placeholder { - color: hsl(var(--color-primary) / 1); - } - .placeholder-primary\/50::placeholder { - color: hsl(var(--color-primary) / 0.5); - } - .ring-primary { - --tw-ring-color: hsl(var(--color-primary) / 1); - } - .ring-primary\/50 { - --tw-ring-color: hsl(var(--color-primary) / 0.5); - } - `) - }) - }) - - test('Theme function in JS can apply alpha values to colors (1)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3b82f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: '#3b82f6' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 50%'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (2)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3b82f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: '#3b82f6' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 0.5'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (3)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: rgb(59 130 246 / var(--my-alpha)); - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: '#3b82f6' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / var(--my-alpha)'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (4)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3c83f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 50%'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (5)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: #3c83f680; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 0.5'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (6)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: hsl(217 91% 60% / var(--my-alpha)); - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / var(--my-alpha)'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function in JS can apply alpha values to colors (7)', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: rgb(var(--foo) / var(--my-alpha)); - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { - blue: { - 500: 'rgb(var(--foo) / )', - }, - }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / var(--my-alpha)'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - test('Theme function prefers existing values in config', () => { - let input = css` - @tailwind utilities; - ` - - let output = css` - .text-foo { - color: purple; - } - ` - - return run(input, { - content: [{ raw: html`text-foo` }], - corePlugins: { textOpacity: false }, - theme: { - colors: { - blue: { - '500 / 50%': 'purple', - }, - }, - extend: { - textColor: ({ theme }) => ({ - foo: theme('colors.blue.500 / 50%'), - }), - }, - }, - }).then((result) => { - expect(result.css).toMatchFormattedCss(output) - expect(result.warnings().length).toBe(0) - }) - }) - - it('should be possible to use an as part of the color definition', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor', 'backgroundOpacity'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-primary { - --tw-bg-opacity: 1; - background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); - } - `) - }) - }) - - it('should be possible to use an as part of the color definition with an opacity modifiers', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor', 'backgroundOpacity'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-primary\/50 { - background-color: rgb(var(--color-primary) / 0.5); - } - `) - }) - }) - - it('should be possible to use an as part of the color definition with an opacity modifiers', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-primary { - background-color: rgb(var(--color-primary) / 1); - } - `) - }) - }) - - it('should be possible to use inside arbitrary values', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['backgroundColor', 'backgroundOpacity'], - theme: { - colors: { - primary: 'rgb(var(--color-primary) / )', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-\[rgb\(var\(--color-primary\)\/\\)\]\/50 { - background-color: rgb(var(--color-primary) / 0.5); - } - `) - }) - }) - - it('Theme functions can reference values with slashes in brackets', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - theme: { - colors: { - 'a/b': '#000000', - }, - extend: { - backgroundColor: ({ theme }) => ({ - foo1: theme('colors[a/b]'), - foo2: theme('colors[a/b]/50%'), - }), - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-foo1 { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - .bg-foo2 { - background-color: #00000080; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-foo1 { - background-color: #000; - } - .bg-foo2 { - background-color: #00000080; - } - `) - }) - }) - - it('works with opacity values defined as a placeholder or a function in when colors is a function', () => { - let config = { - content: [ - { - raw: html` -
- `, - }, - ], - theme: { - colors: () => ({ - foobar1: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, - foobar2: `rgb(255 100 0 / )`, - foobar3: { - 100: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, - 200: `rgb(255 100 0 / )`, - }, - }), - extend: { - backgroundColor: ({ theme }) => ({ - foo10: theme('colors.foobar1'), - foo20: theme('colors.foobar2'), - foo30: theme('colors.foobar3.100'), - foo40: theme('colors.foobar3.200'), - foo11: theme('colors.foobar1 / 50%'), - foo21: theme('colors.foobar2 / 50%'), - foo31: theme('colors.foobar3.100 / 50%'), - foo41: theme('colors.foobar3.200 / 50%'), - }), - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-foo10 { - background-color: #ff6400; - } - .bg-foo11 { - background-color: #ff640080; - } - .bg-foo20 { - --tw-bg-opacity: 1; - background-color: rgb(255 100 0 / var(--tw-bg-opacity)); - } - .bg-foo21 { - background-color: #ff640080; - } - .bg-foo30 { - background-color: #ff6400; - } - .bg-foo31 { - background-color: #ff640080; - } - .bg-foo40 { - --tw-bg-opacity: 1; - background-color: rgb(255 100 0 / var(--tw-bg-opacity)); - } - .bg-foo41 { - background-color: #ff640080; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-foo10 { - background-color: #ff6400; - } - .bg-foo11 { - background-color: #ff640080; - } - .bg-foo20 { - background-color: #ff6400; - } - .bg-foo21 { - background-color: #ff640080; - } - .bg-foo30 { - background-color: #ff6400; - } - .bg-foo31 { - background-color: #ff640080; - } - .bg-foo40 { - background-color: #ff6400; - } - .bg-foo41 { - background-color: #ff640080; - } - `) - }) - }) - - it('The disableColorOpacityUtilitiesByDefault flag disables the color opacity plugins and removes their variables', () => { - let config = { - future: { - disableColorOpacityUtilitiesByDefault: true, - }, - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { - border-color: #93c5fd; - } - .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: #93c5fd80; - } - .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .border-blue-300 { - border-color: #93c5fd; - } - .border-blue-300\/50 { - border-color: #93c5fd80; - } - .border-blue-300\/\[var\(--my-opacity\)\] { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .bg-blue-300 { - background-color: #93c5fd; - } - .bg-blue-300\/50 { - background-color: #93c5fd80; - } - .bg-blue-300\/\[var\(--my-opacity\)\] { - background-color: rgb(147 197 253 / var(--my-opacity)); - } - .text-blue-300 { - color: #93c5fd; - } - .text-blue-300\/50 { - color: #93c5fd80; - } - .text-blue-300\/\[var\(--my-opacity\)\] { - color: rgb(147 197 253 / var(--my-opacity)); - } - .placeholder-blue-300::placeholder { - color: #93c5fd; - } - .placeholder-blue-300\/50::placeholder { - color: #93c5fd80; - } - .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { - color: rgb(147 197 253 / var(--my-opacity)); - } - .ring-blue-300 { - --tw-ring-color: #93c5fd; - } - .ring-blue-300\/50 { - --tw-ring-color: #93c5fd80; - } - .ring-blue-300\/\[var\(--my-opacity\)\] { - --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); - } - `) - }) - }) - - it('You can re-enable any opacity plugin even when disableColorOpacityUtilitiesByDefault is enabled', () => { - let config = { - future: { - disableColorOpacityUtilitiesByDefault: true, - }, - corePlugins: { - backgroundOpacity: true, - borderOpacity: true, - divideOpacity: true, - placeholderOpacity: true, - ringOpacity: true, - textOpacity: true, - }, - content: [ - { - raw: html` -
-
-
-
- `, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 1; - border-color: rgb(147 197 253 / var(--tw-divide-opacity)); - } - .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { - border-color: #93c5fd80; - } - .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-opacity: 0.5; - } - .border-blue-300 { - --tw-border-opacity: 1; - border-color: rgb(147 197 253 / var(--tw-border-opacity)); - } - .border-blue-300\/50 { - border-color: #93c5fd80; - } - .border-blue-300\/\[var\(--my-opacity\)\] { - border-color: rgb(147 197 253 / var(--my-opacity)); - } - .border-opacity-50 { - --tw-border-opacity: 0.5; - } - .bg-blue-300 { - --tw-bg-opacity: 1; - background-color: rgb(147 197 253 / var(--tw-bg-opacity)); - } - .bg-blue-300\/50 { - background-color: #93c5fd80; - } - .bg-blue-300\/\[var\(--my-opacity\)\] { - background-color: rgb(147 197 253 / var(--my-opacity)); - } - .bg-opacity-50 { - --tw-bg-opacity: 0.5; - } - .text-blue-300 { - --tw-text-opacity: 1; - color: rgb(147 197 253 / var(--tw-text-opacity)); - } - .text-blue-300\/50 { - color: #93c5fd80; - } - .text-blue-300\/\[var\(--my-opacity\)\] { - color: rgb(147 197 253 / var(--my-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - .placeholder-blue-300::placeholder { - --tw-placeholder-opacity: 1; - color: rgb(147 197 253 / var(--tw-placeholder-opacity)); - } - .placeholder-blue-300\/50::placeholder { - color: #93c5fd80; - } - .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { - color: rgb(147 197 253 / var(--my-opacity)); - } - .placeholder-opacity-50::placeholder { - --tw-placeholder-opacity: 0.5; - } - .ring-blue-300 { - --tw-ring-opacity: 1; - --tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity)); - } - .ring-blue-300\/50 { - --tw-ring-color: #93c5fd80; - } - .ring-blue-300\/\[var\(--my-opacity\)\] { - --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); - } - .ring-opacity-50 { - --tw-ring-opacity: 0.5; - } - `) - }) - }) - - it('can replace the potential alpha value in rgba/hsla syntax', async () => { - let config = { - content: [{ raw: html`
` }], - theme: { - colors: { - 'primary-rgba': 'rgba(var(--color), 0.1)', - 'primary-hsla': 'hsla(var(--color), 0.1)', - }, - }, - } - - let result = await run('@tailwind utilities', config) + ], + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + }, + } + return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .text-primary-hsla\/50 { - color: hsla(var(--color), 0.5); + .divide-black > :not([hidden]) ~ :not([hidden]), + .border-black { + border-color: #000; } - .text-primary-rgba\/50 { - color: rgba(var(--color), 0.5); + .bg-black { + background-color: #000; + } + .text-black, + .placeholder-black::placeholder { + color: #000; } `) }) }) + +test('colors defined as functions work when opacity plugins are disabled', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: ({ opacityValue }) => + opacityValue === undefined + ? 'rgb(var(--color-primary))' + : `rgb(var(--color-primary) / ${opacityValue})`, + }, + }, + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]), + .border-primary { + border-color: rgb(var(--color-primary)); + } + .bg-primary { + background-color: rgb(var(--color-primary)); + } + .text-primary, + .placeholder-primary::placeholder { + color: rgb(var(--color-primary)); + } + `) + }) +}) + +it('can use defining custom properties for colors (opacity plugins enabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(var(--color-primary) / var(--tw-divide-opacity)); + } + .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 0.5; + } + .border-primary { + --tw-border-opacity: 1; + border-color: rgb(var(--color-primary) / var(--tw-border-opacity)); + } + .border-opacity-50 { + --tw-border-opacity: 0.5; + } + .bg-primary { + --tw-bg-opacity: 1; + background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .text-primary { + --tw-text-opacity: 1; + color: rgb(var(--color-primary) / var(--tw-text-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + .placeholder-primary::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(var(--color-primary) / var(--tw-placeholder-opacity)); + } + .placeholder-opacity-50::placeholder { + --tw-placeholder-opacity: 0.5; + } + .ring-primary { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(var(--color-primary) / var(--tw-ring-opacity)); + } + .ring-opacity-50 { + --tw-ring-opacity: 0.5; + } + `) + }) +}) + +it('can use rgb helper when defining custom properties for colors (opacity plugins disabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + ringOpacity: false, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(var(--color-primary) / 1); + } + .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(var(--color-primary) / 0.5); + } + .border-primary { + border-color: rgb(var(--color-primary) / 1); + } + .border-primary\/50 { + border-color: rgb(var(--color-primary) / 0.5); + } + .bg-primary { + background-color: rgb(var(--color-primary) / 1); + } + .bg-primary\/50 { + background-color: rgb(var(--color-primary) / 0.5); + } + .text-primary { + color: rgb(var(--color-primary) / 1); + } + .text-primary\/50 { + color: rgb(var(--color-primary) / 0.5); + } + .placeholder-primary::placeholder { + color: rgb(var(--color-primary) / 1); + } + .placeholder-primary\/50::placeholder { + color: rgb(var(--color-primary) / 0.5); + } + .ring-primary { + --tw-ring-color: rgb(var(--color-primary) / 1); + } + .ring-primary\/50 { + --tw-ring-color: rgb(var(--color-primary) / 0.5); + } + `) + }) +}) + +it('can use hsl helper when defining custom properties for colors (opacity plugins enabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'hsl(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: hsl(var(--color-primary) / var(--tw-divide-opacity)); + } + .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 0.5; + } + .border-primary { + --tw-border-opacity: 1; + border-color: hsl(var(--color-primary) / var(--tw-border-opacity)); + } + .border-opacity-50 { + --tw-border-opacity: 0.5; + } + .bg-primary { + --tw-bg-opacity: 1; + background-color: hsl(var(--color-primary) / var(--tw-bg-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .text-primary { + --tw-text-opacity: 1; + color: hsl(var(--color-primary) / var(--tw-text-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + .placeholder-primary::placeholder { + --tw-placeholder-opacity: 1; + color: hsl(var(--color-primary) / var(--tw-placeholder-opacity)); + } + .placeholder-opacity-50::placeholder { + --tw-placeholder-opacity: 0.5; + } + .ring-primary { + --tw-ring-opacity: 1; + --tw-ring-color: hsl(var(--color-primary) / var(--tw-ring-opacity)); + } + .ring-opacity-50 { + --tw-ring-opacity: 0.5; + } + `) + }) +}) + +it('can use hsl helper when defining custom properties for colors (opacity plugins disabled)', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + theme: { + colors: { + primary: 'hsl(var(--color-primary) / )', + }, + }, + corePlugins: { + backgroundOpacity: false, + borderOpacity: false, + divideOpacity: false, + placeholderOpacity: false, + textOpacity: false, + ringOpacity: false, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-primary > :not([hidden]) ~ :not([hidden]) { + border-color: hsl(var(--color-primary) / 1); + } + .divide-primary\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: hsl(var(--color-primary) / 0.5); + } + .border-primary { + border-color: hsl(var(--color-primary) / 1); + } + .border-primary\/50 { + border-color: hsl(var(--color-primary) / 0.5); + } + .bg-primary { + background-color: hsl(var(--color-primary) / 1); + } + .bg-primary\/50 { + background-color: hsl(var(--color-primary) / 0.5); + } + .text-primary { + color: hsl(var(--color-primary) / 1); + } + .text-primary\/50 { + color: hsl(var(--color-primary) / 0.5); + } + .placeholder-primary::placeholder { + color: hsl(var(--color-primary) / 1); + } + .placeholder-primary\/50::placeholder { + color: hsl(var(--color-primary) / 0.5); + } + .ring-primary { + --tw-ring-color: hsl(var(--color-primary) / 1); + } + .ring-primary\/50 { + --tw-ring-color: hsl(var(--color-primary) / 0.5); + } + `) + }) +}) + +test('Theme function in JS can apply alpha values to colors (1)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3b82f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (2)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3b82f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 0.5'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (3)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(59 130 246 / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: '#3b82f6' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (4)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3c83f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (5)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: #3c83f680; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 0.5'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (6)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: hsl(217 91% 60% / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { blue: { 500: 'hsl(217, 91%, 60%)' } }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function in JS can apply alpha values to colors (7)', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: rgb(var(--foo) / var(--my-alpha)); + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { + blue: { + 500: 'rgb(var(--foo) / )', + }, + }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / var(--my-alpha)'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +test('Theme function prefers existing values in config', () => { + let input = css` + @tailwind utilities; + ` + + let output = css` + .text-foo { + color: purple; + } + ` + + return run(input, { + content: [{ raw: html`text-foo` }], + corePlugins: { textOpacity: false }, + theme: { + colors: { + blue: { + '500 / 50%': 'purple', + }, + }, + extend: { + textColor: ({ theme }) => ({ + foo: theme('colors.blue.500 / 50%'), + }), + }, + }, + }).then((result) => { + expect(result.css).toMatchFormattedCss(output) + expect(result.warnings().length).toBe(0) + }) +}) + +it('should be possible to use an as part of the color definition', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor', 'backgroundOpacity'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-primary { + --tw-bg-opacity: 1; + background-color: rgb(var(--color-primary) / var(--tw-bg-opacity)); + } + `) + }) +}) + +it('should be possible to use an as part of the color definition with an opacity modifiers', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor', 'backgroundOpacity'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-primary\/50 { + background-color: rgb(var(--color-primary) / 0.5); + } + `) + }) +}) + +it('should be possible to use an as part of the color definition with an opacity modifiers', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-primary { + background-color: rgb(var(--color-primary) / 1); + } + `) + }) +}) + +it('should be possible to use inside arbitrary values', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['backgroundColor', 'backgroundOpacity'], + theme: { + colors: { + primary: 'rgb(var(--color-primary) / )', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-\[rgb\(var\(--color-primary\)\/\\)\]\/50 { + background-color: rgb(var(--color-primary) / 0.5); + } + `) + }) +}) + +it('Theme functions can reference values with slashes in brackets', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + theme: { + colors: { + 'a/b': '#000000', + }, + extend: { + backgroundColor: ({ theme }) => ({ + foo1: theme('colors[a/b]'), + foo2: theme('colors[a/b]/50%'), + }), + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-foo1 { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .bg-foo2 { + background-color: #00000080; + } + `) + }) +}) + +it('works with opacity values defined as a placeholder or a function in when colors is a function', () => { + let config = { + content: [ + { + raw: html` +
+ `, + }, + ], + theme: { + colors: () => ({ + foobar1: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, + foobar2: `rgb(255 100 0 / )`, + foobar3: { + 100: ({ opacityValue }) => `rgb(255 100 0 / ${opacityValue ?? '100%'})`, + 200: `rgb(255 100 0 / )`, + }, + }), + extend: { + backgroundColor: ({ theme }) => ({ + foo10: theme('colors.foobar1'), + foo20: theme('colors.foobar2'), + foo30: theme('colors.foobar3.100'), + foo40: theme('colors.foobar3.200'), + foo11: theme('colors.foobar1 / 50%'), + foo21: theme('colors.foobar2 / 50%'), + foo31: theme('colors.foobar3.100 / 50%'), + foo41: theme('colors.foobar3.200 / 50%'), + }), + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-foo10 { + background-color: #ff6400; + } + .bg-foo11 { + background-color: #ff640080; + } + .bg-foo20 { + --tw-bg-opacity: 1; + background-color: rgb(255 100 0 / var(--tw-bg-opacity)); + } + .bg-foo21 { + background-color: #ff640080; + } + .bg-foo30 { + background-color: #ff6400; + } + .bg-foo31 { + background-color: #ff640080; + } + .bg-foo40 { + --tw-bg-opacity: 1; + background-color: rgb(255 100 0 / var(--tw-bg-opacity)); + } + .bg-foo41 { + background-color: #ff640080; + } + `) + }) +}) + +it('The disableColorOpacityUtilitiesByDefault flag disables the color opacity plugins and removes their variables', () => { + let config = { + future: { + disableColorOpacityUtilitiesByDefault: true, + }, + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { + border-color: #93c5fd; + } + .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: #93c5fd80; + } + .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .border-blue-300 { + border-color: #93c5fd; + } + .border-blue-300\/50 { + border-color: #93c5fd80; + } + .border-blue-300\/\[var\(--my-opacity\)\] { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .bg-blue-300 { + background-color: #93c5fd; + } + .bg-blue-300\/50 { + background-color: #93c5fd80; + } + .bg-blue-300\/\[var\(--my-opacity\)\] { + background-color: rgb(147 197 253 / var(--my-opacity)); + } + .text-blue-300 { + color: #93c5fd; + } + .text-blue-300\/50 { + color: #93c5fd80; + } + .text-blue-300\/\[var\(--my-opacity\)\] { + color: rgb(147 197 253 / var(--my-opacity)); + } + .placeholder-blue-300::placeholder { + color: #93c5fd; + } + .placeholder-blue-300\/50::placeholder { + color: #93c5fd80; + } + .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { + color: rgb(147 197 253 / var(--my-opacity)); + } + .ring-blue-300 { + --tw-ring-color: #93c5fd; + } + .ring-blue-300\/50 { + --tw-ring-color: #93c5fd80; + } + .ring-blue-300\/\[var\(--my-opacity\)\] { + --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); + } + `) + }) +}) + +it('You can re-enable any opacity plugin even when disableColorOpacityUtilitiesByDefault is enabled', () => { + let config = { + future: { + disableColorOpacityUtilitiesByDefault: true, + }, + corePlugins: { + backgroundOpacity: true, + borderOpacity: true, + divideOpacity: true, + placeholderOpacity: true, + ringOpacity: true, + textOpacity: true, + }, + content: [ + { + raw: html` +
+
+
+
+ `, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .divide-blue-300 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(147 197 253 / var(--tw-divide-opacity)); + } + .divide-blue-300\/50 > :not([hidden]) ~ :not([hidden]) { + border-color: #93c5fd80; + } + .divide-blue-300\/\[var\(--my-opacity\)\] > :not([hidden]) ~ :not([hidden]) { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .divide-opacity-50 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 0.5; + } + .border-blue-300 { + --tw-border-opacity: 1; + border-color: rgb(147 197 253 / var(--tw-border-opacity)); + } + .border-blue-300\/50 { + border-color: #93c5fd80; + } + .border-blue-300\/\[var\(--my-opacity\)\] { + border-color: rgb(147 197 253 / var(--my-opacity)); + } + .border-opacity-50 { + --tw-border-opacity: 0.5; + } + .bg-blue-300 { + --tw-bg-opacity: 1; + background-color: rgb(147 197 253 / var(--tw-bg-opacity)); + } + .bg-blue-300\/50 { + background-color: #93c5fd80; + } + .bg-blue-300\/\[var\(--my-opacity\)\] { + background-color: rgb(147 197 253 / var(--my-opacity)); + } + .bg-opacity-50 { + --tw-bg-opacity: 0.5; + } + .text-blue-300 { + --tw-text-opacity: 1; + color: rgb(147 197 253 / var(--tw-text-opacity)); + } + .text-blue-300\/50 { + color: #93c5fd80; + } + .text-blue-300\/\[var\(--my-opacity\)\] { + color: rgb(147 197 253 / var(--my-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + .placeholder-blue-300::placeholder { + --tw-placeholder-opacity: 1; + color: rgb(147 197 253 / var(--tw-placeholder-opacity)); + } + .placeholder-blue-300\/50::placeholder { + color: #93c5fd80; + } + .placeholder-blue-300\/\[var\(--my-opacity\)\]::placeholder { + color: rgb(147 197 253 / var(--my-opacity)); + } + .placeholder-opacity-50::placeholder { + --tw-placeholder-opacity: 0.5; + } + .ring-blue-300 { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(147 197 253 / var(--tw-ring-opacity)); + } + .ring-blue-300\/50 { + --tw-ring-color: #93c5fd80; + } + .ring-blue-300\/\[var\(--my-opacity\)\] { + --tw-ring-color: rgb(147 197 253 / var(--my-opacity)); + } + .ring-opacity-50 { + --tw-ring-opacity: 0.5; + } + `) + }) +}) + +it('can replace the potential alpha value in rgba/hsla syntax', async () => { + let config = { + content: [{ raw: html`
` }], + theme: { + colors: { + 'primary-rgba': 'rgba(var(--color), 0.1)', + 'primary-hsla': 'hsla(var(--color), 0.1)', + }, + }, + } + + let result = await run('@tailwind utilities', config) + + expect(result.css).toMatchFormattedCss(css` + .text-primary-hsla\/50 { + color: hsla(var(--color), 0.5); + } + .text-primary-rgba\/50 { + color: rgba(var(--color), 0.5); + } + `) +}) diff --git a/tests/oxide.test.js b/tests/oxide.test.js deleted file mode 100644 index d2a697626..000000000 --- a/tests/oxide.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import { crosscheck, run, html, css, defaults } from './util/run' - -crosscheck(({ stable, oxide }) => { - stable.test.todo('space-x uses physical properties') - oxide.test('space-x uses logical properties', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); - } - `) - }) - }) -}) diff --git a/tests/parallel-variants.test.js b/tests/parallel-variants.test.js index a4d4dfc8f..61fb2cb33 100644 --- a/tests/parallel-variants.test.js +++ b/tests/parallel-variants.test.js @@ -1,138 +1,136 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('basic parallel variants', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function test({ addVariant }) { - addVariant('test', ['& *::test', '&::test']) - }, - ], - } +test('basic parallel variants', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function test({ addVariant }) { + addVariant('test', ['& *::test', '&::test']) + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-normal { - font-weight: 400; - } - .test\:font-bold ::test { - font-weight: 700; - } - .test\:font-medium ::test { - font-weight: 500; - } - .hover\:test\:font-black ::test:hover { - font-weight: 900; - } - .test\:font-bold::test { - font-weight: 700; - } - .test\:font-medium::test { - font-weight: 500; - } - .hover\:test\:font-black::test:hover { - font-weight: 900; - } - `) - }) - }) - - test('parallel variants can be generated using a function that returns parallel variants', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function test({ addVariant }) { - addVariant('test', () => ['& *::test', '&::test']) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-normal { - font-weight: 400; - } - .test\:font-bold ::test { - font-weight: 700; - } - .test\:font-medium ::test { - font-weight: 500; - } - .test\:font-bold::test { - font-weight: 700; - } - .test\:font-medium::test { - font-weight: 500; - } - .hover\:test\:font-black ::test:hover { - font-weight: 900; - } - .hover\:test\:font-black::test:hover { - font-weight: 900; - } - `) - }) - }) - - test('a function that returns parallel variants can modify the container', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function test({ addVariant }) { - addVariant('test', ({ container }) => { - container.walkDecls((decl) => { - decl.value = `calc(0 + ${decl.value})` - }) - - return ['& *::test', '&::test'] - }) - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-normal { - font-weight: 400; - } - .test\:font-bold ::test { - font-weight: 700; - } - .test\:font-medium ::test { - font-weight: 500; - } - .test\:font-bold::test { - font-weight: 700; - } - .test\:font-medium::test { - font-weight: 500; - } - .hover\:test\:font-black ::test:hover { - font-weight: 900; - } - .hover\:test\:font-black::test:hover { - font-weight: 900; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-normal { + font-weight: 400; + } + .test\:font-bold ::test { + font-weight: 700; + } + .test\:font-medium ::test { + font-weight: 500; + } + .hover\:test\:font-black ::test:hover { + font-weight: 900; + } + .test\:font-bold::test { + font-weight: 700; + } + .test\:font-medium::test { + font-weight: 500; + } + .hover\:test\:font-black::test:hover { + font-weight: 900; + } + `) + }) +}) + +test('parallel variants can be generated using a function that returns parallel variants', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function test({ addVariant }) { + addVariant('test', () => ['& *::test', '&::test']) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-normal { + font-weight: 400; + } + .test\:font-bold ::test { + font-weight: 700; + } + .test\:font-medium ::test { + font-weight: 500; + } + .test\:font-bold::test { + font-weight: 700; + } + .test\:font-medium::test { + font-weight: 500; + } + .hover\:test\:font-black ::test:hover { + font-weight: 900; + } + .hover\:test\:font-black::test:hover { + font-weight: 900; + } + `) + }) +}) + +test('a function that returns parallel variants can modify the container', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function test({ addVariant }) { + addVariant('test', ({ container }) => { + container.walkDecls((decl) => { + decl.value = `calc(0 + ${decl.value})` + }) + + return ['& *::test', '&::test'] + }) + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-normal { + font-weight: 400; + } + .test\:font-bold ::test { + font-weight: 700; + } + .test\:font-medium ::test { + font-weight: 500; + } + .test\:font-bold::test { + font-weight: 700; + } + .test\:font-medium::test { + font-weight: 500; + } + .hover\:test\:font-black ::test:hover { + font-weight: 900; + } + .hover\:test\:font-black::test:hover { + font-weight: 900; + } + `) }) }) diff --git a/tests/parseAnimationValue.test.js b/tests/parseAnimationValue.test.js index 098178079..293d6fbec 100644 --- a/tests/parseAnimationValue.test.js +++ b/tests/parseAnimationValue.test.js @@ -1,203 +1,200 @@ import parseAnimationValue from '../src/util/parseAnimationValue' -import { crosscheck } from './util/run' -crosscheck(() => { - describe('Tailwind Defaults', () => { - it.each([ - [ - 'spin 1s linear infinite', - { - value: 'spin 1s linear infinite', - name: 'spin', - duration: '1s', - timingFunction: 'linear', - iterationCount: 'infinite', - }, - ], - [ - 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - { - value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - name: 'ping', - duration: '1s', - timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', - iterationCount: 'infinite', - }, - ], - [ - 'bounce 1s infinite', - { - value: 'bounce 1s infinite', - name: 'bounce', - duration: '1s', - iterationCount: 'infinite', - }, - ], - ])('should be possible to parse: "%s"', (input, expected) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0]).toEqual(expected) - }) - }) - - describe('css variables', () => { - it('should be possible to use css variables', () => { - let parsed = parseAnimationValue('jump var(--animation-duration, 10s) linear infinite') - expect(parsed[0]).toEqual({ - value: 'jump var(--animation-duration, 10s) linear infinite', - name: 'jump', +describe('Tailwind Defaults', () => { + it.each([ + [ + 'spin 1s linear infinite', + { + value: 'spin 1s linear infinite', + name: 'spin', + duration: '1s', timingFunction: 'linear', iterationCount: 'infinite', - unknown: ['var(--animation-duration, 10s)'], - }) - }) - }) - - describe('MDN Examples', () => { - it.each([ - [ - '3s ease-in 1s 2 reverse both paused slidein', - { - value: '3s ease-in 1s 2 reverse both paused slidein', - delay: '1s', - direction: 'reverse', - duration: '3s', - fillMode: 'both', - iterationCount: '2', - name: 'slidein', - playState: 'paused', - timingFunction: 'ease-in', - }, - ], - [ - 'slidein 3s linear 1s', - { - value: 'slidein 3s linear 1s', - delay: '1s', - duration: '3s', - name: 'slidein', - timingFunction: 'linear', - }, - ], - ['slidein 3s', { value: 'slidein 3s', duration: '3s', name: 'slidein' }], - ])('should be possible to parse: "%s"', (input, expected) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0]).toEqual(expected) - }) - }) - - describe('duration & delay', () => { - it.each([ - // Positive seconds (integer) - ['spin 2s 1s linear', { duration: '2s', delay: '1s' }], - - // Negative seconds (integer) - ['spin -2s -1s linear', { duration: '-2s', delay: '-1s' }], - - // Positive seconds (float) - ['spin 2.321s 1.321s linear', { duration: '2.321s', delay: '1.321s' }], - - // Negative seconds (float) - ['spin -2.321s -1.321s linear', { duration: '-2.321s', delay: '-1.321s' }], - - // Positive milliseconds (integer) - ['spin 200ms 100ms linear', { duration: '200ms', delay: '100ms' }], - - // Negative milliseconds (integer) - ['spin -200ms -100ms linear', { duration: '-200ms', delay: '-100ms' }], - - // Positive milliseconds (float) - ['spin 200.321ms 100.321ms linear', { duration: '200.321ms', delay: '100.321ms' }], - - // Negative milliseconds (float) - ['spin -200.321ms -100.321ms linear', { duration: '-200.321ms', delay: '-100.321ms' }], - ])('should be possible to parse "%s" into %o', (input, { duration, delay }) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0].duration).toEqual(duration) - expect(parsed[0].delay).toEqual(delay) - }) - }) - - describe('iteration count', () => { - it.each([ - // Number - ['1 spin 200s 100s linear', '1'], - ['spin 2 200s 100s linear', '2'], - ['spin 200s 3 100s linear', '3'], - ['spin 200s 100s 4 linear', '4'], - ['spin 200s 100s linear 5', '5'], - - // Infinite - ['infinite spin 200s 100s linear', 'infinite'], - ['spin infinite 200s 100s linear', 'infinite'], - ['spin 200s infinite 100s linear', 'infinite'], - ['spin 200s 100s infinite linear', 'infinite'], - ['spin 200s 100s linear infinite', 'infinite'], - ])( - 'should be possible to parse "%s" with an iteraction count of "%s"', - (input, iterationCount) => { - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(1) - expect(parsed[0].iterationCount).toEqual(iterationCount) - } - ) - }) - - describe('multiple animations', () => { - it('should be possible to parse multiple applications at once', () => { - const input = [ - 'spin 1s linear infinite', - 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', - ].join(',') - - const parsed = parseAnimationValue(input) - expect(parsed).toHaveLength(3) - expect(parsed).toEqual([ - { - value: 'spin 1s linear infinite', - name: 'spin', - duration: '1s', - timingFunction: 'linear', - iterationCount: 'infinite', - }, - { - value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - name: 'ping', - duration: '1s', - timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', - iterationCount: 'infinite', - }, - { - value: 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', - name: 'pulse', - duration: '2s', - timingFunction: 'cubic-bezier(0.4, 0, 0.6)', - iterationCount: 'infinite', - }, - ]) - }) - }) - - it.each` - input | value | direction | playState | fillMode | iterationCount | timingFunction | duration | delay | name - ${'1s spin 1s infinite'} | ${'1s spin 1s infinite'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'spin'} - ${'infinite infinite 1s 1s'} | ${'infinite infinite 1s 1s'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'infinite'} - ${'ease 1s ease 1s'} | ${'ease 1s ease 1s'} | ${undefined} | ${undefined} | ${undefined} | ${undefined} | ${'ease'} | ${'1s'} | ${'1s'} | ${'ease'} - ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'1s 2s name normal paused backwards infinite ease-in'} | ${'1s 2s name normal paused backwards infinite ease-in'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${'2s name normal paused backwards infinite ease-in 1s'} | ${'2s name normal paused backwards infinite ease-in 1s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'2s'} | ${'1s'} | ${'name'} - ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - ${' name normal paused backwards infinite ease-in 1s 2s '} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} - `('should parse "$input" correctly', ({ input, ...expected }) => { - let parsed = parseAnimationValue(input) + }, + ], + [ + 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + { + value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + name: 'ping', + duration: '1s', + timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', + iterationCount: 'infinite', + }, + ], + [ + 'bounce 1s infinite', + { + value: 'bounce 1s infinite', + name: 'bounce', + duration: '1s', + iterationCount: 'infinite', + }, + ], + ])('should be possible to parse: "%s"', (input, expected) => { + const parsed = parseAnimationValue(input) expect(parsed).toHaveLength(1) expect(parsed[0]).toEqual(expected) }) }) + +describe('css variables', () => { + it('should be possible to use css variables', () => { + let parsed = parseAnimationValue('jump var(--animation-duration, 10s) linear infinite') + expect(parsed[0]).toEqual({ + value: 'jump var(--animation-duration, 10s) linear infinite', + name: 'jump', + timingFunction: 'linear', + iterationCount: 'infinite', + unknown: ['var(--animation-duration, 10s)'], + }) + }) +}) + +describe('MDN Examples', () => { + it.each([ + [ + '3s ease-in 1s 2 reverse both paused slidein', + { + value: '3s ease-in 1s 2 reverse both paused slidein', + delay: '1s', + direction: 'reverse', + duration: '3s', + fillMode: 'both', + iterationCount: '2', + name: 'slidein', + playState: 'paused', + timingFunction: 'ease-in', + }, + ], + [ + 'slidein 3s linear 1s', + { + value: 'slidein 3s linear 1s', + delay: '1s', + duration: '3s', + name: 'slidein', + timingFunction: 'linear', + }, + ], + ['slidein 3s', { value: 'slidein 3s', duration: '3s', name: 'slidein' }], + ])('should be possible to parse: "%s"', (input, expected) => { + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0]).toEqual(expected) + }) +}) + +describe('duration & delay', () => { + it.each([ + // Positive seconds (integer) + ['spin 2s 1s linear', { duration: '2s', delay: '1s' }], + + // Negative seconds (integer) + ['spin -2s -1s linear', { duration: '-2s', delay: '-1s' }], + + // Positive seconds (float) + ['spin 2.321s 1.321s linear', { duration: '2.321s', delay: '1.321s' }], + + // Negative seconds (float) + ['spin -2.321s -1.321s linear', { duration: '-2.321s', delay: '-1.321s' }], + + // Positive milliseconds (integer) + ['spin 200ms 100ms linear', { duration: '200ms', delay: '100ms' }], + + // Negative milliseconds (integer) + ['spin -200ms -100ms linear', { duration: '-200ms', delay: '-100ms' }], + + // Positive milliseconds (float) + ['spin 200.321ms 100.321ms linear', { duration: '200.321ms', delay: '100.321ms' }], + + // Negative milliseconds (float) + ['spin -200.321ms -100.321ms linear', { duration: '-200.321ms', delay: '-100.321ms' }], + ])('should be possible to parse "%s" into %o', (input, { duration, delay }) => { + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0].duration).toEqual(duration) + expect(parsed[0].delay).toEqual(delay) + }) +}) + +describe('iteration count', () => { + it.each([ + // Number + ['1 spin 200s 100s linear', '1'], + ['spin 2 200s 100s linear', '2'], + ['spin 200s 3 100s linear', '3'], + ['spin 200s 100s 4 linear', '4'], + ['spin 200s 100s linear 5', '5'], + + // Infinite + ['infinite spin 200s 100s linear', 'infinite'], + ['spin infinite 200s 100s linear', 'infinite'], + ['spin 200s infinite 100s linear', 'infinite'], + ['spin 200s 100s infinite linear', 'infinite'], + ['spin 200s 100s linear infinite', 'infinite'], + ])( + 'should be possible to parse "%s" with an iteraction count of "%s"', + (input, iterationCount) => { + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0].iterationCount).toEqual(iterationCount) + } + ) +}) + +describe('multiple animations', () => { + it('should be possible to parse multiple applications at once', () => { + const input = [ + 'spin 1s linear infinite', + 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', + ].join(',') + + const parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(3) + expect(parsed).toEqual([ + { + value: 'spin 1s linear infinite', + name: 'spin', + duration: '1s', + timingFunction: 'linear', + iterationCount: 'infinite', + }, + { + value: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + name: 'ping', + duration: '1s', + timingFunction: 'cubic-bezier(0, 0, 0.2, 1)', + iterationCount: 'infinite', + }, + { + value: 'pulse 2s cubic-bezier(0.4, 0, 0.6) infinite', + name: 'pulse', + duration: '2s', + timingFunction: 'cubic-bezier(0.4, 0, 0.6)', + iterationCount: 'infinite', + }, + ]) + }) +}) + +it.each` + input | value | direction | playState | fillMode | iterationCount | timingFunction | duration | delay | name + ${'1s spin 1s infinite'} | ${'1s spin 1s infinite'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'spin'} + ${'infinite infinite 1s 1s'} | ${'infinite infinite 1s 1s'} | ${undefined} | ${undefined} | ${undefined} | ${'infinite'} | ${undefined} | ${'1s'} | ${'1s'} | ${'infinite'} + ${'ease 1s ease 1s'} | ${'ease 1s ease 1s'} | ${undefined} | ${undefined} | ${undefined} | ${undefined} | ${'ease'} | ${'1s'} | ${'1s'} | ${'ease'} + ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal paused backwards infinite ease-in 1s 2s name'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'paused backwards infinite ease-in 1s 2s name normal'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'backwards infinite ease-in 1s 2s name normal paused'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'infinite ease-in 1s 2s name normal paused backwards'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'ease-in 1s 2s name normal paused backwards infinite'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'1s 2s name normal paused backwards infinite ease-in'} | ${'1s 2s name normal paused backwards infinite ease-in'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${'2s name normal paused backwards infinite ease-in 1s'} | ${'2s name normal paused backwards infinite ease-in 1s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'2s'} | ${'1s'} | ${'name'} + ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} + ${' name normal paused backwards infinite ease-in 1s 2s '} | ${'name normal paused backwards infinite ease-in 1s 2s'} | ${'normal'} | ${'paused'} | ${'backwards'} | ${'infinite'} | ${'ease-in'} | ${'1s'} | ${'2s'} | ${'name'} +`('should parse "$input" correctly', ({ input, ...expected }) => { + let parsed = parseAnimationValue(input) + expect(parsed).toHaveLength(1) + expect(parsed[0]).toEqual(expected) +}) diff --git a/tests/parseObjectStyles.test.js b/tests/parseObjectStyles.test.js index c6121977f..b823801ee 100644 --- a/tests/parseObjectStyles.test.js +++ b/tests/parseObjectStyles.test.js @@ -1,319 +1,317 @@ import parseObjectStyles from '../src/util/parseObjectStyles' import postcss from 'postcss' -import { crosscheck, css } from './util/run' +import { css } from './util/run' function toCss(nodes) { return postcss.root({ nodes }).toString() } -crosscheck(() => { - test('it parses simple single class definitions', () => { - const result = parseObjectStyles({ - '.foobar': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foobar { - color: #fff; - background-color: red; - padding: 1rem; - } - `) +test('it parses simple single class definitions', () => { + const result = parseObjectStyles({ + '.foobar': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + }, }) - test('it parses multiple class definitions', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - }, - '.bar': { - width: '200px', - height: '100px', - }, - }) + expect(toCss(result)).toMatchFormattedCss(css` + .foobar { + color: #fff; + background-color: red; + padding: 1rem; + } + `) +}) - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - .bar { - width: 200px; - height: 100px; - } - `) +test('it parses multiple class definitions', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + }, + '.bar': { + width: '200px', + height: '100px', + }, }) - test('it parses nested pseudo-selectors', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '&:hover': { - backgroundColor: 'orange', - }, - '&:focus': { - backgroundColor: 'blue', - }, - }, - }) + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + .bar { + width: 200px; + height: 100px; + } + `) +}) - expect(toCss(result)).toMatchFormattedCss(css` +test('it parses nested pseudo-selectors', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '&:hover': { + backgroundColor: 'orange', + }, + '&:focus': { + backgroundColor: 'blue', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + .foo:hover { + background-color: orange; + } + .foo:focus { + background-color: #00f; + } + `) +}) + +test('it parses top-level media queries', () => { + const result = parseObjectStyles({ + '@media (min-width: 200px)': { + '.foo': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + @media (min-width: 200px) { .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - .foo:hover { background-color: orange; } - .foo:focus { - background-color: #00f; - } - `) - }) + } + `) +}) - test('it parses top-level media queries', () => { - const result = parseObjectStyles({ +test('it parses nested media queries', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', '@media (min-width: 200px)': { - '.foo': { - backgroundColor: 'orange', - }, + backgroundColor: 'orange', }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - @media (min-width: 200px) { - .foo { - background-color: orange; - } - } - `) + }, }) - test('it parses nested media queries', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + @media (min-width: 200px) { + .foo { + background-color: orange; + } + } + `) +}) + +test('it bubbles nested screen rules', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '@screen sm': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + @screen sm { + .foo { + background-color: orange; + } + } + `) +}) + +test('it parses pseudo-selectors in nested media queries', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '&:hover': { '@media (min-width: 200px)': { backgroundColor: 'orange', }, }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @media (min-width: 200px) { - .foo { - background-color: orange; - } - } - `) + }, }) - test('it bubbles nested screen rules', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '@screen sm': { - backgroundColor: 'orange', - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @screen sm { - .foo { - background-color: orange; - } - } - `) - }) - - test('it parses pseudo-selectors in nested media queries', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '&:hover': { - '@media (min-width: 200px)': { - backgroundColor: 'orange', - }, - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @media (min-width: 200px) { - .foo:hover { - background-color: orange; - } - } - `) - }) - - test('it parses descendant selectors', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '.bar': { - backgroundColor: 'orange', - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - .foo .bar { + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + @media (min-width: 200px) { + .foo:hover { background-color: orange; } - `) + } + `) +}) + +test('it parses descendant selectors', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '.bar': { + backgroundColor: 'orange', + }, + }, }) - test('it parses nested multi-class selectors', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + .foo .bar { + background-color: orange; + } + `) +}) + +test('it parses nested multi-class selectors', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '&.bar': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + .foo.bar { + background-color: orange; + } + `) +}) + +test('it parses nested multi-class selectors in media queries', () => { + const result = parseObjectStyles({ + '.foo': { + backgroundColor: 'red', + color: 'white', + padding: '1rem', + '@media (min-width: 200px)': { '&.bar': { backgroundColor: 'orange', }, }, - }) + }, + }) - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + color: #fff; + background-color: red; + padding: 1rem; + } + @media (min-width: 200px) { .foo.bar { background-color: orange; } - `) - }) - - test('it parses nested multi-class selectors in media queries', () => { - const result = parseObjectStyles({ - '.foo': { - backgroundColor: 'red', - color: 'white', - padding: '1rem', - '@media (min-width: 200px)': { - '&.bar': { - backgroundColor: 'orange', - }, - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - color: #fff; - background-color: red; - padding: 1rem; - } - @media (min-width: 200px) { - .foo.bar { - background-color: orange; - } - } - `) - }) - - test('it strips empty selectors when nesting', () => { - const result = parseObjectStyles({ - '.foo': { - '.bar': { - backgroundColor: 'orange', - }, - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo .bar { - background-color: orange; - } - `) - }) - - test('it can parse an array of styles', () => { - const result = parseObjectStyles([ - { - '.foo': { - backgroundColor: 'orange', - }, - }, - { - '.bar': { - backgroundColor: 'red', - }, - }, - { - '.foo': { - backgroundColor: 'blue', - }, - }, - ]) - - expect(toCss(result)).toMatchFormattedCss(css` - .foo { - background-color: orange; - } - .bar { - background-color: red; - } - .foo { - background-color: #00f; - } - `) - }) - - test('custom properties preserve their case', () => { - const result = parseObjectStyles({ - ':root': { - '--colors-aColor-500': '0', - }, - }) - - expect(toCss(result)).toMatchFormattedCss(css` - :root { - --colors-aColor-500: 0; - } - `) - }) + } + `) +}) + +test('it strips empty selectors when nesting', () => { + const result = parseObjectStyles({ + '.foo': { + '.bar': { + backgroundColor: 'orange', + }, + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo .bar { + background-color: orange; + } + `) +}) + +test('it can parse an array of styles', () => { + const result = parseObjectStyles([ + { + '.foo': { + backgroundColor: 'orange', + }, + }, + { + '.bar': { + backgroundColor: 'red', + }, + }, + { + '.foo': { + backgroundColor: 'blue', + }, + }, + ]) + + expect(toCss(result)).toMatchFormattedCss(css` + .foo { + background-color: orange; + } + .bar { + background-color: red; + } + .foo { + background-color: #00f; + } + `) +}) + +test('custom properties preserve their case', () => { + const result = parseObjectStyles({ + ':root': { + '--colors-aColor-500': '0', + }, + }) + + expect(toCss(result)).toMatchFormattedCss(css` + :root { + --colors-aColor-500: 0; + } + `) }) diff --git a/tests/plugins/divide.test.js b/tests/plugins/divide.test.js index 314233bea..37bd012ac 100644 --- a/tests/plugins/divide.test.js +++ b/tests/plugins/divide.test.js @@ -1,102 +1,91 @@ -import { crosscheck, run, html, css, defaults } from '../util/run' +import { run, html, css, defaults } from '../util/run' -crosscheck(({ stable, oxide }) => { - it('should add the divide styles for divide-y and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } +it('should add the divide styles for divide-y and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchCss(css` + ${defaults} - .divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - `) - }) - }) - - it('should add the divide styles for divide-x and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - stable.expect(result.css).toMatchCss(css` - ${defaults} - .divide-x > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-right-width: calc(1px * var(--tw-divide-x-reverse)); - border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); - } - `) - - oxide.expect(result.css).toMatchCss(css` - ${defaults} - .divide-x > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(1px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); - } - `) - }) - }) - - it('should add the divide styles for divide-y-reverse and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .divide-y-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 1; - } - `) - }) - }) - - it('should add the divide styles for divide-x-reverse and a default border color', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .divide-x-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 1; - } - `) - }) - }) - - it('should only inject the base styles once if we use divide and border at the same time', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` - ${defaults} - .divide-y > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); - } - .border-r { - border-right-width: 1px; - } - `) - }) + .divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + `) + }) +}) + +it('should add the divide styles for divide-x and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchCss(css` + ${defaults} + .divide-x > :not([hidden]) ~ :not([hidden]) { + --tw-divide-x-reverse: 0; + border-right-width: calc(1px * var(--tw-divide-x-reverse)); + border-left-width: calc(1px * calc(1 - var(--tw-divide-x-reverse))); + } + `) + }) +}) + +it('should add the divide styles for divide-y-reverse and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchCss(css` + ${defaults} + .divide-y-reverse > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 1; + } + `) + }) +}) + +it('should add the divide styles for divide-x-reverse and a default border color', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchCss(css` + ${defaults} + .divide-x-reverse > :not([hidden]) ~ :not([hidden]) { + --tw-divide-x-reverse: 1; + } + `) + }) +}) + +it('should only inject the base styles once if we use divide and border at the same time', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchCss(css` + ${defaults} + .divide-y > :not([hidden]) ~ :not([hidden]) { + --tw-divide-y-reverse: 0; + border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); + border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); + } + .border-r { + border-right-width: 1px; + } + `) }) }) diff --git a/tests/plugins/fontFamily.test.js b/tests/plugins/fontFamily.test.js index 1170dac8e..f5718909d 100644 --- a/tests/plugins/fontFamily.test.js +++ b/tests/plugins/fontFamily.test.js @@ -1,101 +1,99 @@ -import { crosscheck, run, html, css } from '../util/run' +import { run, html, css } from '../util/run' -crosscheck(() => { - test('font-family utilities can be defined as a string', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: 'Helvetica, Arial, sans-serif', - }, +test('font-family utilities can be defined as a string', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: 'Helvetica, Arial, sans-serif', }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-family: Helvetica, Arial, sans-serif; + } + `) }) +}) - test('font-family utilities can be defined as an array', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: ['Helvetica', 'Arial', 'sans-serif'], - }, +test('font-family utilities can be defined as an array', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: ['Helvetica', 'Arial', 'sans-serif'], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-family: Helvetica, Arial, sans-serif; + } + `) }) +}) - test('font-family values are not automatically escaped', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: ["'Exo 2'", 'sans-serif'], - }, +test('font-family values are not automatically escaped', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: ["'Exo 2'", 'sans-serif'], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-family: 'Exo 2', sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-family: 'Exo 2', sans-serif; + } + `) }) +}) - test('font-feature-settings can be provided when families are defined as a string', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: ['Helvetica, Arial, sans-serif', { fontFeatureSettings: '"cv11", "ss01"' }], - }, +test('font-feature-settings can be provided when families are defined as a string', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: ['Helvetica, Arial, sans-serif', { fontFeatureSettings: '"cv11", "ss01"' }], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-feature-settings: 'cv11', 'ss01'; - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-feature-settings: 'cv11', 'ss01'; + font-family: Helvetica, Arial, sans-serif; + } + `) }) +}) - test('font-feature-settings can be provided when families are defined as an array', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontFamily: { - sans: [['Helvetica', 'Arial', 'sans-serif'], { fontFeatureSettings: '"cv11", "ss01"' }], - }, +test('font-feature-settings can be provided when families are defined as an array', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontFamily: { + sans: [['Helvetica', 'Arial', 'sans-serif'], { fontFeatureSettings: '"cv11", "ss01"' }], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-sans { - font-feature-settings: 'cv11', 'ss01'; - font-family: Helvetica, Arial, sans-serif; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-sans { + font-feature-settings: 'cv11', 'ss01'; + font-family: Helvetica, Arial, sans-serif; + } + `) }) }) diff --git a/tests/plugins/fontSize.test.js b/tests/plugins/fontSize.test.js index 08e88bb76..32214650f 100644 --- a/tests/plugins/fontSize.test.js +++ b/tests/plugins/fontSize.test.js @@ -1,197 +1,195 @@ -import { crosscheck, run, html, css } from '../util/run' +import { run, html, css } from '../util/run' -crosscheck(() => { - test('font-size utilities can include a default line-height', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', '24px'], - lg: ['20px', '28px'], - }, +test('font-size utilities can include a default line-height', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', '24px'], + lg: ['20px', '28px'], }, - } + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - font-size: 20px; - line-height: 28px; - } - .text-md { - font-size: 16px; - line-height: 24px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a default letter-spacing', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', { letterSpacing: '-0.01em' }], - lg: ['20px', { letterSpacing: '-0.02em' }], - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - letter-spacing: -0.02em; - font-size: 20px; - } - .text-md { - letter-spacing: -0.01em; - font-size: 16px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a default line-height and letter-spacing', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', { lineHeight: '24px', letterSpacing: '-0.01em' }], - lg: ['20px', { lineHeight: '28px', letterSpacing: '-0.02em' }], - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - letter-spacing: -0.02em; - font-size: 20px; - line-height: 28px; - } - .text-md { - letter-spacing: -0.01em; - font-size: 16px; - line-height: 24px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a font-weight', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - fontSize: { - sm: '12px', - md: ['16px', { lineHeight: '24px', fontWeight: 500 }], - lg: ['20px', { lineHeight: '28px', fontWeight: 'bold' }], - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-lg { - font-size: 20px; - font-weight: bold; - line-height: 28px; - } - .text-md { - font-size: 16px; - font-weight: 500; - line-height: 24px; - } - .text-sm { - font-size: 12px; - } - `) - }) - }) - - test('font-size utilities can include a line-height modifier', () => { - let config = { - content: [ - { - raw: html`
-
-
-
-
-
-
`, - }, - ], - theme: { - fontSize: { - sm: ['12px', '20px'], - base: ['16px', '24px'], - }, - lineHeight: { - 6: '24px', - 7: '28px', - 8: '32px', - }, - }, - } - - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` - .text-\[13px\]\/6 { - font-size: 13px; - line-height: 24px; - } - .text-\[17px\]\/\[23px\] { - font-size: 17px; - line-height: 23px; - } - .text-sm { - font-size: 12px; - line-height: 20px; - } - .text-sm\/6 { - font-size: 12px; - line-height: 24px; - } - .text-sm\/\[21px\] { - font-size: 12px; - line-height: 21px; - } - @media (min-width: 768px) { - .md\:text-\[19px\]\/8 { - font-size: 19px; - line-height: 32px; - } - .md\:text-\[21px\]\/\[29px\] { - font-size: 21px; - line-height: 29px; - } - .md\:text-base { - font-size: 16px; - line-height: 24px; - } - .md\:text-base\/7 { - font-size: 16px; - line-height: 28px; - } - .md\:text-base\/\[33px\] { - font-size: 16px; - line-height: 33px; - } - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .text-lg { + font-size: 20px; + line-height: 28px; + } + .text-md { + font-size: 16px; + line-height: 24px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a default letter-spacing', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', { letterSpacing: '-0.01em' }], + lg: ['20px', { letterSpacing: '-0.02em' }], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .text-lg { + letter-spacing: -0.02em; + font-size: 20px; + } + .text-md { + letter-spacing: -0.01em; + font-size: 16px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a default line-height and letter-spacing', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', { lineHeight: '24px', letterSpacing: '-0.01em' }], + lg: ['20px', { lineHeight: '28px', letterSpacing: '-0.02em' }], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .text-lg { + letter-spacing: -0.02em; + font-size: 20px; + line-height: 28px; + } + .text-md { + letter-spacing: -0.01em; + font-size: 16px; + line-height: 24px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a font-weight', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + fontSize: { + sm: '12px', + md: ['16px', { lineHeight: '24px', fontWeight: 500 }], + lg: ['20px', { lineHeight: '28px', fontWeight: 'bold' }], + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .text-lg { + font-size: 20px; + font-weight: bold; + line-height: 28px; + } + .text-md { + font-size: 16px; + font-weight: 500; + line-height: 24px; + } + .text-sm { + font-size: 12px; + } + `) + }) +}) + +test('font-size utilities can include a line-height modifier', () => { + let config = { + content: [ + { + raw: html`
+
+
+
+
+
+
`, + }, + ], + theme: { + fontSize: { + sm: ['12px', '20px'], + base: ['16px', '24px'], + }, + lineHeight: { + 6: '24px', + 7: '28px', + 8: '32px', + }, + }, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchCss(css` + .text-\[13px\]\/6 { + font-size: 13px; + line-height: 24px; + } + .text-\[17px\]\/\[23px\] { + font-size: 17px; + line-height: 23px; + } + .text-sm { + font-size: 12px; + line-height: 20px; + } + .text-sm\/6 { + font-size: 12px; + line-height: 24px; + } + .text-sm\/\[21px\] { + font-size: 12px; + line-height: 21px; + } + @media (min-width: 768px) { + .md\:text-\[19px\]\/8 { + font-size: 19px; + line-height: 32px; + } + .md\:text-\[21px\]\/\[29px\] { + font-size: 21px; + line-height: 29px; + } + .md\:text-base { + font-size: 16px; + line-height: 24px; + } + .md\:text-base\/7 { + font-size: 16px; + line-height: 28px; + } + .md\:text-base\/\[33px\] { + font-size: 16px; + line-height: 33px; + } + } + `) }) }) diff --git a/tests/plugins/gradientColorStops.test.js b/tests/plugins/gradientColorStops.test.js index de79cc8fc..c9647d50f 100644 --- a/tests/plugins/gradientColorStops.test.js +++ b/tests/plugins/gradientColorStops.test.js @@ -1,191 +1,155 @@ -import { crosscheck, run, html, css } from '../util/run' +import { run, html, css } from '../util/run' -crosscheck(({ stable, oxide }) => { - test('opacity variables are given to colors defined as closures', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - theme: { - colors: { - primary: ({ opacityVariable, opacityValue }) => { - if (opacityValue !== undefined) { - return `rgba(31,31,31,${opacityValue})` - } - - if (opacityVariable !== undefined) { - return `rgba(31,31,31,var(${opacityVariable},1))` - } - - return `rgb(31,31,31)` - }, - secondary: 'hsl(10, 50%, 50%)', - }, - opacity: { - 50: '0.5', - }, +test('opacity variables are given to colors defined as closures', () => { + let config = { + content: [ + { + raw: html`
`, }, - } + ], + theme: { + colors: { + primary: ({ opacityVariable, opacityValue }) => { + if (opacityValue !== undefined) { + return `rgba(31,31,31,${opacityValue})` + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .from-primary { - --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-secondary { - --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-primary { - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .via-secondary { - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .to-primary { - --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); - } - .to-secondary { - --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); - } - .text-primary { - --tw-text-opacity: 1; - color: rgba(31, 31, 31, var(--tw-text-opacity)); - } - .text-secondary { - --tw-text-opacity: 1; - color: hsl(10 50% 50% / var(--tw-text-opacity)); - } - .text-opacity-50 { - --tw-text-opacity: 0.5; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .from-primary { - --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-secondary { - --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .via-primary { - --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .via-secondary { - --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .to-primary { - --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); - } - .to-secondary { - --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); - } - .text-primary { - color: #1f1f1f; - } - .text-secondary { - color: #bf5540; - } - `) - }) - }) + if (opacityVariable !== undefined) { + return `rgba(31,31,31,var(${opacityVariable},1))` + } - test('gradient color stop position', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
- `, + return `rgb(31,31,31)` }, - ], - theme: {}, - } + secondary: 'hsl(10, 50%, 50%)', + }, + opacity: { + 50: '0.5', + }, + }, + } - return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); - } - .from-\[--from-value\] { - --tw-gradient-from: var(--from-value) var(--tw-gradient-from-position); - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-red-500 { - --tw-gradient-from: #ef4444 var(--tw-gradient-from-position); - --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); - } - .from-10\% { - --tw-gradient-from-position: 10%; - } - .from-\[11\%\] { - --tw-gradient-from-position: 11%; - } - .from-\[12px\] { - --tw-gradient-from-position: 12px; - } - .via-\[--via-value\] { - --tw-gradient-to: #fff0 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), - var(--via-value) var(--tw-gradient-via-position), var(--tw-gradient-to); - } - .via-pink-500 { - --tw-gradient-to: #ec489900 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #ec4899 var(--tw-gradient-via-position), - var(--tw-gradient-to); - } - .via-20\% { - --tw-gradient-via-position: 20%; - } - .via-\[12\%\] { - --tw-gradient-via-position: 12%; - } - .via-\[123px\] { - --tw-gradient-via-position: 123px; - } - .to-\[--to-value\] { - --tw-gradient-to: var(--to-value) var(--tw-gradient-to-position); - } - .to-violet-400 { - --tw-gradient-to: #a78bfa var(--tw-gradient-to-position); - } - .to-30\% { - --tw-gradient-to-position: 30%; - } - .to-\[13\%\] { - --tw-gradient-to-position: 13%; - } - .to-\[14px\] { - --tw-gradient-to-position: 14px; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .from-primary { + --tw-gradient-from: #1f1f1f var(--tw-gradient-from-position); + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-secondary { + --tw-gradient-from: #bf5540 var(--tw-gradient-from-position); + --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .via-primary { + --tw-gradient-to: #1f1f1f00 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), #1f1f1f var(--tw-gradient-via-position), + var(--tw-gradient-to); + } + .via-secondary { + --tw-gradient-to: #bf554000 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), #bf5540 var(--tw-gradient-via-position), + var(--tw-gradient-to); + } + .to-primary { + --tw-gradient-to: #1f1f1f var(--tw-gradient-to-position); + } + .to-secondary { + --tw-gradient-to: #bf5540 var(--tw-gradient-to-position); + } + .text-primary { + --tw-text-opacity: 1; + color: rgba(31, 31, 31, var(--tw-text-opacity)); + } + .text-secondary { + --tw-text-opacity: 1; + color: hsl(10 50% 50% / var(--tw-text-opacity)); + } + .text-opacity-50 { + --tw-text-opacity: 0.5; + } + `) + }) +}) + +test('gradient color stop position', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + theme: {}, + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-gradient-to-r { + background-image: linear-gradient(to right, var(--tw-gradient-stops)); + } + .from-\[--from-value\] { + --tw-gradient-from: var(--from-value) var(--tw-gradient-from-position); + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-red-500 { + --tw-gradient-from: #ef4444 var(--tw-gradient-from-position); + --tw-gradient-to: #ef444400 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); + } + .from-10\% { + --tw-gradient-from-position: 10%; + } + .from-\[11\%\] { + --tw-gradient-from-position: 11%; + } + .from-\[12px\] { + --tw-gradient-from-position: 12px; + } + .via-\[--via-value\] { + --tw-gradient-to: #fff0 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), + var(--via-value) var(--tw-gradient-via-position), var(--tw-gradient-to); + } + .via-pink-500 { + --tw-gradient-to: #ec489900 var(--tw-gradient-to-position); + --tw-gradient-stops: var(--tw-gradient-from), #ec4899 var(--tw-gradient-via-position), + var(--tw-gradient-to); + } + .via-20\% { + --tw-gradient-via-position: 20%; + } + .via-\[12\%\] { + --tw-gradient-via-position: 12%; + } + .via-\[123px\] { + --tw-gradient-via-position: 123px; + } + .to-\[--to-value\] { + --tw-gradient-to: var(--to-value) var(--tw-gradient-to-position); + } + .to-violet-400 { + --tw-gradient-to: #a78bfa var(--tw-gradient-to-position); + } + .to-30\% { + --tw-gradient-to-position: 30%; + } + .to-\[13\%\] { + --tw-gradient-to-position: 13%; + } + .to-\[14px\] { + --tw-gradient-to-position: 14px; + } + `) }) }) diff --git a/tests/prefers-contrast.test.js b/tests/prefers-contrast.test.js index e3b940da8..52420ee1e 100644 --- a/tests/prefers-contrast.test.js +++ b/tests/prefers-contrast.test.js @@ -1,102 +1,71 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - it('should be possible to use contrast-more and contrast-less variants', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } +it('should be possible to use contrast-more and contrast-less variants', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - ${defaults} - .bg-white { + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + .bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); + } + @media (prefers-contrast: more) { + .contrast-more\:bg-pink-500 { + --tw-bg-opacity: 1; + background-color: rgb(236 72 153 / var(--tw-bg-opacity)); + } + } + @media (prefers-contrast: less) { + .contrast-less\:bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + } + `) + }) +}) + +it('dark mode should appear after the contrast variants', () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (prefers-contrast: more) { + .contrast-more\:bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + } + @media (prefers-color-scheme: dark) { + .dark\:bg-white { --tw-bg-opacity: 1; background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } - @media (prefers-contrast: more) { - .contrast-more\:bg-pink-500 { - --tw-bg-opacity: 1; - background-color: rgb(236 72 153 / var(--tw-bg-opacity)); - } - } - @media (prefers-contrast: less) { - .contrast-less\:bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - ${defaults} - .bg-white { - background-color: #fff; - } - @media (prefers-contrast: more) { - .contrast-more\:bg-pink-500 { - background-color: #ec4899; - } - } - @media (prefers-contrast: less) { - .contrast-less\:bg-black { - background-color: #000; - } - } - `) - }) - }) - - it('dark mode should appear after the contrast variants', () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-contrast: more) { - .contrast-more\:bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - } - @media (prefers-color-scheme: dark) { - .dark\:bg-white { - --tw-bg-opacity: 1; - background-color: rgb(255 255 255 / var(--tw-bg-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (prefers-contrast: more) { - .contrast-more\:bg-black { - background-color: #000; - } - } - @media (prefers-color-scheme: dark) { - .dark\:bg-white { - background-color: #fff; - } - } - `) - }) + } + `) }) }) diff --git a/tests/prefix.test.js b/tests/prefix.test.js index ea3d041ff..c9c0e5f25 100644 --- a/tests/prefix.test.js +++ b/tests/prefix.test.js @@ -1,625 +1,609 @@ -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - oxide.test.todo('prefix') - stable.test('prefix', () => { - let config = { - prefix: 'tw-', - darkMode: 'class', - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - theme: { - animation: { - spin: 'spin 1s linear infinite', - ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', - }, - keyframes: { - spin: { to: { transform: 'rotate(360deg)' } }, - }, +test('prefix', () => { + let config = { + prefix: 'tw-', + darkMode: 'class', + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, }, - plugins: [ - function ({ addComponents, addUtilities }) { - addComponents({ - '.btn-prefix': { + ], + corePlugins: { preflight: false }, + theme: { + animation: { + spin: 'spin 1s linear infinite', + ping: 'ping 1s cubic-bezier(0, 0, 0.2, 1) infinite', + }, + keyframes: { + spin: { to: { transform: 'rotate(360deg)' } }, + }, + }, + plugins: [ + function ({ addComponents, addUtilities }) { + addComponents({ + '.btn-prefix': { + button: 'yes', + }, + }) + addComponents( + { + '.btn-no-prefix': { button: 'yes', }, - }) - addComponents( - { - '.btn-no-prefix': { - button: 'yes', - }, - }, - { respectPrefix: false } - ) - addUtilities({ - '.custom-util-prefix': { + }, + { respectPrefix: false } + ) + addUtilities({ + '.custom-util-prefix': { + button: 'no', + }, + }) + addUtilities( + { + '.custom-util-no-prefix': { button: 'no', }, - }) - addUtilities( - { - '.custom-util-no-prefix': { - button: 'no', - }, - }, - { respectPrefix: false } - ) - }, - ], - } - - let input = css` - @tailwind base; - @tailwind components; - @layer components { - .custom-component { - @apply tw-font-bold dark:group-hover:tw-font-normal; - } - } - @tailwind utilities; - @layer utilities { - .custom-utility { - foo: bar; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - .tw-container { - width: 100%; - } - @media (min-width: 640px) { - .tw-container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .tw-container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .tw-container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .tw-container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .tw-container { - max-width: 1536px; - } - } - .tw-btn-prefix, - .btn-no-prefix { - button: yes; - } - .custom-component { - font-weight: 700; - } - :is(.tw-dark .tw-group:hover .custom-component) { - font-weight: 400; - } - .tw--ml-4 { - margin-left: -1rem; - } - .tw-animate-ping { - animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; - } - @keyframes tw-spin { - to { - transform: rotate(360deg); - } - } - .tw-animate-spin { - animation: 1s linear infinite tw-spin; - } - .tw-font-bold { - font-weight: 700; - } - .tw-custom-util-prefix, - .custom-util-no-prefix { - button: no; - } - .tw-group:hover .group-hover\:focus-within\:tw-text-left:focus-within { - text-align: left; - } - :is([dir='rtl'] .rtl\:active\:tw-text-center:active) { - text-align: center; - } - @media (prefers-reduced-motion: no-preference) { - .motion-safe\:hover\:tw-text-center:hover { - text-align: center; - } - } - :is(.tw-dark .dark\:tw-bg-\[rgb\(255\,0\,0\)\]) { - --tw-bg-opacity: 1; - background-color: rgb(255 0 0 / var(--tw-bg-opacity)); - } - :is(.tw-dark .dark\:focus\:tw-text-left:focus) { - text-align: left; - } - @media (min-width: 768px) { - .md\:tw--ml-5 { - margin-left: -1.25rem; - } - .md\:hover\:tw--ml-6:hover { - margin-left: -1.5rem; - } - .md\:hover\:tw-text-right:hover { - text-align: right; - } - } - `) - }) - }) - - oxide.test.todo('negative values: marker before prefix') - stable.test('negative values: marker before prefix', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .-tw-top-1 { - top: -0.25rem; - } - `) - }) - - oxide.test.todo('negative values: marker after prefix') - stable.test('negative values: marker after prefix', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .tw--top-1 { - top: -0.25rem; - } - `) - }) - - oxide.test.todo('negative values: marker before prefix and arbitrary value') - stable.test('negative values: marker before prefix and arbitrary value', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .-tw-top-\[1px\] { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: marker after prefix and arbitrary value') - stable.test('negative values: marker after prefix and arbitrary value', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .tw--top-\[1px\] { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: no marker and arbitrary value') - stable.test('negative values: no marker and arbitrary value', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .tw-top-\[-1px\] { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: variant versions') - stable.test('negative values: variant versions', async () => { - let config = { - prefix: 'tw-', - content: [ - { - raw: html` -
-
-
- - -
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .hover\:-tw-top-1:hover { - top: -0.25rem; - } - .hover\:-tw-top-\[1px\]:hover { - top: -1px; - } - .hover\:tw--top-1:hover { - top: -0.25rem; - } - .hover\:tw--top-\[1px\]:hover, - .hover\:tw-top-\[-1px\]:hover { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: prefix and apply') - stable.test('negative values: prefix and apply', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - - .a { - @apply hover:tw--top-1; - } - .b { - @apply hover:-tw-top-1; - } - .c { - @apply hover:-tw-top-[1px]; - } - .d { - @apply hover:tw--top-[1px]; - } - .e { - @apply hover:tw-top-[-1px]; - } - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .a:hover, - .b:hover { - top: -0.25rem; - } - .c:hover, - .d:hover, - .e:hover { - top: -1px; - } - `) - }) - - oxide.test.todo('negative values: prefix in the safelist') - stable.test('negative values: prefix in the safelist', async () => { - let config = { - prefix: 'tw-', - safelist: [{ pattern: /-tw-top-1/g }, { pattern: /tw--top-1/g }], - theme: { - inset: { - 1: '0.25rem', - }, + }, + { respectPrefix: false } + ) }, - content: [{ raw: html`` }], - corePlugins: { preflight: false }, - } + ], + } - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .-tw-top-1, - .tw--top-1 { - top: -0.25rem; + let input = css` + @tailwind base; + @tailwind components; + @layer components { + .custom-component { + @apply tw-font-bold dark:group-hover:tw-font-normal; } - `) - }) - - oxide.test.todo('prefix with negative values and variants in the safelist') - stable.test('prefix with negative values and variants in the safelist', async () => { - let config = { - prefix: 'tw-', - safelist: [ - { pattern: /-tw-top-1/, variants: ['hover', 'sm:hover'] }, - { pattern: /tw--top-1/, variants: ['hover', 'sm:hover'] }, - ], - theme: { - inset: { - 1: '0.25rem', - }, - }, - content: [{ raw: html`` }], - corePlugins: { preflight: false }, } + @tailwind utilities; + @layer utilities { + .custom-utility { + foo: bar; + } + } + ` - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - const result = await run(input, config) - + return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .-tw-top-1, - .tw--top-1, - .hover\:-tw-top-1:hover, - .hover\:tw--top-1:hover { - top: -0.25rem; + ${defaults} + .tw-container { + width: 100%; } @media (min-width: 640px) { - .sm\:hover\:-tw-top-1:hover, - .sm\:hover\:tw--top-1:hover { - top: -0.25rem; + .tw-container { + max-width: 640px; } } - `) - }) - - oxide.test.todo('prefix does not detect and generate unnecessary classes') - stable.test('prefix does not detect and generate unnecessary classes', async () => { - let config = { - prefix: 'tw-_', - content: [{ raw: html`-aaa-filter aaaa-table aaaa-hidden` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css``) - }) - - oxide.test.todo('supports prefixed utilities using arbitrary values') - stable.test('supports prefixed utilities using arbitrary values', async () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`foo` }], - corePlugins: { preflight: false }, - } - - let input = css` - .foo { - @apply tw-text-[color:rgb(var(--button-background,var(--primary-button-background)))]; - @apply tw-ease-[cubic-bezier(0.77,0,0.175,1)]; - @apply tw-rounded-[min(4px,var(--input-border-radius))]; - } - ` - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .foo { - color: rgb(var(--button-background, var(--primary-button-background))); - border-radius: min(4px, var(--input-border-radius)); - transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1); - } - `) - }) - - oxide.test.todo('supports non-word prefixes (1)') - stable.test('supports non-word prefixes (1)', async () => { - let config = { - prefix: '@', - content: [ - { - raw: html` -
-
-
-
-
-
- - -
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .my-utility { - color: orange; + @media (min-width: 768px) { + .tw-container { + max-width: 768px; } } - .foo { - @apply @text-white; - @apply [background-color:red]; + @media (min-width: 1024px) { + .tw-container { + max-width: 1024px; + } } - ` - - const result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .\@bg-black { + @media (min-width: 1280px) { + .tw-container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .tw-container { + max-width: 1536px; + } + } + .tw-btn-prefix, + .btn-no-prefix { + button: yes; + } + .custom-component { + font-weight: 700; + } + :is(.tw-dark .tw-group:hover .custom-component) { + font-weight: 400; + } + .tw--ml-4 { + margin-left: -1rem; + } + .tw-animate-ping { + animation: 1s cubic-bezier(0, 0, 0.2, 1) infinite ping; + } + @keyframes tw-spin { + to { + transform: rotate(360deg); + } + } + .tw-animate-spin { + animation: 1s linear infinite tw-spin; + } + .tw-font-bold { + font-weight: 700; + } + .tw-custom-util-prefix, + .custom-util-no-prefix { + button: no; + } + .tw-group:hover .group-hover\:focus-within\:tw-text-left:focus-within { + text-align: left; + } + :is([dir='rtl'] .rtl\:active\:tw-text-center:active) { + text-align: center; + } + @media (prefers-reduced-motion: no-preference) { + .motion-safe\:hover\:tw-text-center:hover { + text-align: center; + } + } + :is(.tw-dark .dark\:tw-bg-\[rgb\(255\,0\,0\)\]) { --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + background-color: rgb(255 0 0 / var(--tw-bg-opacity)); } - .\@underline { - text-decoration-line: underline; + :is(.tw-dark .dark\:focus\:tw-text-left:focus) { + text-align: left; } - .my-utility { - color: orange; - } - .foo { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - background-color: red; - } - .hover\:before\:\@content-\[\'Hovering\'\]:hover:before { - --tw-content: 'Hovering'; - content: var(--tw-content); - } - `) - }) - - oxide.test.todo('supports non-word prefixes (2)') - stable.test('supports non-word prefixes (2)', async () => { - let config = { - prefix: '@]$', - content: [ - { - raw: html` -
-
-
-
-
-
- - -
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .my-utility { - color: orange; + @media (min-width: 768px) { + .md\:tw--ml-5 { + margin-left: -1.25rem; + } + .md\:hover\:tw--ml-6:hover { + margin-left: -1.5rem; + } + .md\:hover\:tw-text-right:hover { + text-align: right; } - } - .foo { - @apply @]$text-white; - @apply [background-color:red]; - } - ` - - const result = await run(input, config) - - // TODO: The class `.hover\:before\:\@\]\$content-\[\'Hovering\'\]:hover::before` is not generated - // This happens because of the parenthesis/brace/bracket clipping performed on candidates - - expect(result.css).toMatchFormattedCss(css` - .\@\]\$bg-black { - --tw-bg-opacity: 1; - background-color: rgb(0 0 0 / var(--tw-bg-opacity)); - } - .\@\]\$underline { - text-decoration-line: underline; - } - .my-utility { - color: orange; - } - .foo { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - background-color: red; } `) }) }) + +test('negative values: marker before prefix', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-1 { + top: -0.25rem; + } + `) +}) + +test('negative values: marker after prefix', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .tw--top-1 { + top: -0.25rem; + } + `) +}) + +test('negative values: marker before prefix and arbitrary value', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-\[1px\] { + top: -1px; + } + `) +}) + +test('negative values: marker after prefix and arbitrary value', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .tw--top-\[1px\] { + top: -1px; + } + `) +}) + +test('negative values: no marker and arbitrary value', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .tw-top-\[-1px\] { + top: -1px; + } + `) +}) + +test('negative values: variant versions', async () => { + let config = { + prefix: 'tw-', + content: [ + { + raw: html` +
+
+
+ + +
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .hover\:-tw-top-1:hover { + top: -0.25rem; + } + .hover\:-tw-top-\[1px\]:hover { + top: -1px; + } + .hover\:tw--top-1:hover { + top: -0.25rem; + } + .hover\:tw--top-\[1px\]:hover, + .hover\:tw-top-\[-1px\]:hover { + top: -1px; + } + `) +}) + +test('negative values: prefix and apply', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + + .a { + @apply hover:tw--top-1; + } + .b { + @apply hover:-tw-top-1; + } + .c { + @apply hover:-tw-top-[1px]; + } + .d { + @apply hover:tw--top-[1px]; + } + .e { + @apply hover:tw-top-[-1px]; + } + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .a:hover, + .b:hover { + top: -0.25rem; + } + .c:hover, + .d:hover, + .e:hover { + top: -1px; + } + `) +}) + +test('negative values: prefix in the safelist', async () => { + let config = { + prefix: 'tw-', + safelist: [{ pattern: /-tw-top-1/g }, { pattern: /tw--top-1/g }], + theme: { + inset: { + 1: '0.25rem', + }, + }, + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-1, + .tw--top-1 { + top: -0.25rem; + } + `) +}) + +test('prefix with negative values and variants in the safelist', async () => { + let config = { + prefix: 'tw-', + safelist: [ + { pattern: /-tw-top-1/, variants: ['hover', 'sm:hover'] }, + { pattern: /tw--top-1/, variants: ['hover', 'sm:hover'] }, + ], + theme: { + inset: { + 1: '0.25rem', + }, + }, + content: [{ raw: html`` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .-tw-top-1, + .tw--top-1, + .hover\:-tw-top-1:hover, + .hover\:tw--top-1:hover { + top: -0.25rem; + } + @media (min-width: 640px) { + .sm\:hover\:-tw-top-1:hover, + .sm\:hover\:tw--top-1:hover { + top: -0.25rem; + } + } + `) +}) + +test('prefix does not detect and generate unnecessary classes', async () => { + let config = { + prefix: 'tw-_', + content: [{ raw: html`-aaa-filter aaaa-table aaaa-hidden` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css``) +}) + +test('supports prefixed utilities using arbitrary values', async () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`foo` }], + corePlugins: { preflight: false }, + } + + let input = css` + .foo { + @apply tw-text-[color:rgb(var(--button-background,var(--primary-button-background)))]; + @apply tw-ease-[cubic-bezier(0.77,0,0.175,1)]; + @apply tw-rounded-[min(4px,var(--input-border-radius))]; + } + ` + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .foo { + color: rgb(var(--button-background, var(--primary-button-background))); + border-radius: min(4px, var(--input-border-radius)); + transition-timing-function: cubic-bezier(0.77, 0, 0.175, 1); + } + `) +}) + +test('supports non-word prefixes (1)', async () => { + let config = { + prefix: '@', + content: [ + { + raw: html` +
+
+
+
+
+
+ + +
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .my-utility { + color: orange; + } + } + .foo { + @apply @text-white; + @apply [background-color:red]; + } + ` + + const result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .\@bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .\@underline { + text-decoration-line: underline; + } + .my-utility { + color: orange; + } + .foo { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + background-color: red; + } + .hover\:before\:\@content-\[\'Hovering\'\]:hover:before { + --tw-content: 'Hovering'; + content: var(--tw-content); + } + `) +}) + +test('supports non-word prefixes (2)', async () => { + let config = { + prefix: '@]$', + content: [ + { + raw: html` +
+
+
+
+
+
+ + +
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .my-utility { + color: orange; + } + } + .foo { + @apply @]$text-white; + @apply [background-color:red]; + } + ` + + const result = await run(input, config) + + // TODO: The class `.hover\:before\:\@\]\$content-\[\'Hovering\'\]:hover::before` is not generated + // This happens because of the parenthesis/brace/bracket clipping performed on candidates + + expect(result.css).toMatchFormattedCss(css` + .\@\]\$bg-black { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); + } + .\@\]\$underline { + text-decoration-line: underline; + } + .my-utility { + color: orange; + } + .foo { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + background-color: red; + } + `) +}) diff --git a/tests/prefixSelector.test.js b/tests/prefixSelector.test.js index c7db08d03..92fd6194f 100644 --- a/tests/prefixSelector.test.js +++ b/tests/prefixSelector.test.js @@ -1,20 +1,17 @@ import prefix from '../src/util/prefixSelector' -import { crosscheck } from './util/run' -crosscheck(() => { - test('it prefixes classes with the provided prefix', () => { - expect(prefix('tw-', '.foo')).toEqual('.tw-foo') - }) - - test('it properly prefixes selectors with non-standard characters', () => { - expect(prefix('tw-', '.hello\\:world')).toEqual('.tw-hello\\:world') - expect(prefix('tw-', '.foo\\/bar')).toEqual('.tw-foo\\/bar') - expect(prefix('tw-', '.wew\\.lad')).toEqual('.tw-wew\\.lad') - }) - - test('it prefixes all classes in a selector', () => { - expect(prefix('tw-', '.btn-blue .w-1\\/4 > h1.text-xl + a .bar')).toEqual( - '.tw-btn-blue .tw-w-1\\/4 > h1.tw-text-xl + a .tw-bar' - ) - }) +test('it prefixes classes with the provided prefix', () => { + expect(prefix('tw-', '.foo')).toEqual('.tw-foo') +}) + +test('it properly prefixes selectors with non-standard characters', () => { + expect(prefix('tw-', '.hello\\:world')).toEqual('.tw-hello\\:world') + expect(prefix('tw-', '.foo\\/bar')).toEqual('.tw-foo\\/bar') + expect(prefix('tw-', '.wew\\.lad')).toEqual('.tw-wew\\.lad') +}) + +test('it prefixes all classes in a selector', () => { + expect(prefix('tw-', '.btn-blue .w-1\\/4 > h1.text-xl + a .bar')).toEqual( + '.tw-btn-blue .tw-w-1\\/4 > h1.tw-text-xl + a .tw-bar' + ) }) diff --git a/tests/preflight.test.js b/tests/preflight.test.js index 4f6f722c7..ad654999e 100644 --- a/tests/preflight.test.js +++ b/tests/preflight.test.js @@ -1,25 +1,23 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('preflight has a correct border color fallback', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - borderColor: ({ theme }) => theme('colors'), - }, - plugins: [], - corePlugins: { preflight: true }, - } +it('preflight has a correct border color fallback', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + borderColor: ({ theme }) => theme('colors'), + }, + plugins: [], + corePlugins: { preflight: true }, + } - let input = css` - @tailwind base; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable.expect(result.css).toContain(`border-color: currentColor;`) - // Lightning CSS optimizes this to just `border-color: 0 solid;` based on the br value. - oxide.expect(result.css).toContain(`border: 0 solid;`) - }) + return run(input, config).then((result) => { + // Lightning CSS optimizes this to just `border-color: 0 solid;` because `currentcolor` is the default user-agent stylesheet value. + // https://drafts.csswg.org/css-backgrounds/#border-color + expect(result.css).toContain(`border: 0 solid;`) }) }) diff --git a/tests/raw-content.oxide.test.css b/tests/raw-content.oxide.test.css deleted file mode 100644 index aa5abd127..000000000 --- a/tests/raw-content.oxide.test.css +++ /dev/null @@ -1,759 +0,0 @@ -.container { - width: 100%; -} -@media (min-width: 640px) { - .container { - max-width: 640px; - } -} -@media (min-width: 768px) { - .container { - max-width: 768px; - } -} -@media (min-width: 1024px) { - .container { - max-width: 1024px; - } -} -@media (min-width: 1280px) { - .container { - max-width: 1280px; - } -} -@media (min-width: 1536px) { - .container { - max-width: 1536px; - } -} -.sr-only { - width: 1px; - height: 1px; - clip: rect(0, 0, 0, 0); - white-space: nowrap; - border-width: 0; - margin: -1px; - padding: 0; - position: absolute; - overflow: hidden; -} -.pointer-events-none { - pointer-events: none; -} -.invisible { - visibility: hidden; -} -.collapse { - visibility: collapse; -} -.absolute { - position: absolute; -} -.inset-0 { - inset: 0; -} -.inset-x-2 { - left: 0.5rem; - right: 0.5rem; -} -.inset-y-4 { - top: 1rem; - bottom: 1rem; -} -.bottom-12 { - bottom: 3rem; -} -.left-16 { - left: 4rem; -} -.right-8 { - right: 2rem; -} -.top-6 { - top: 1.5rem; -} -.isolate { - isolation: isolate; -} -.isolation-auto { - isolation: auto; -} -.z-30 { - z-index: 30; -} -.order-2 { - order: 2; -} -.order-last { - order: 9999; -} -.col-span-3 { - grid-column: span 3 / span 3; -} -.col-start-1 { - grid-column-start: 1; -} -.col-end-4 { - grid-column-end: 4; -} -.row-span-2 { - grid-row: span 2 / span 2; -} -.row-start-3 { - grid-row-start: 3; -} -.row-end-5 { - grid-row-end: 5; -} -.float-right { - float: right; -} -.clear-left { - clear: left; -} -.m-4 { - margin: 1rem; -} -.mx-auto { - margin-left: auto; - margin-right: auto; -} -.my-2 { - margin-top: 0.5rem; - margin-bottom: 0.5rem; -} -.mb-3 { - margin-bottom: 0.75rem; -} -.ml-4 { - margin-left: 1rem; -} -.mr-1 { - margin-right: 0.25rem; -} -.mt-0 { - margin-top: 0; -} -.box-border { - box-sizing: border-box; -} -.inline-grid { - display: inline-grid; -} -.hidden { - display: none; -} -.h-16 { - height: 4rem; -} -.max-h-screen { - max-height: 100vh; -} -.min-h-0 { - min-height: 0; -} -.w-12 { - width: 3rem; -} -.min-w-min { - min-width: min-content; -} -.max-w-full { - max-width: 100%; -} -.flex-1 { - flex: 1; -} -.flex-shrink { - flex-shrink: 1; -} -.flex-shrink-0 { - flex-shrink: 0; -} -.flex-grow { - flex-grow: 1; -} -.flex-grow-0 { - flex-grow: 0; -} -.table-fixed { - table-layout: fixed; -} -.caption-top { - caption-side: top; -} -.caption-bottom { - caption-side: bottom; -} -.border-collapse { - border-collapse: collapse; -} -.origin-top-right { - transform-origin: 100% 0; -} -.-translate-x-3 { - --tw-translate-x: -0.75rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.-translate-x-4 { - --tw-translate-x: -1rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-x-5 { - --tw-translate-x: 1.25rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.translate-y-6 { - --tw-translate-y: 1.5rem; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-x-12 { - --tw-skew-x: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.skew-y-12 { - --tw-skew-y: 12deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.scale-95 { - --tw-scale-x: 0.95; - --tw-scale-y: 0.95; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform { - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.transform-gpu { - transform: translate3d(var(--tw-translate-x), var(--tw-translate-y), 0) rotate(var(--tw-rotate)) - skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) - scaleY(var(--tw-scale-y)); -} -.animate-none { - animation: none; -} -@keyframes spin { - to { - transform: rotate(360deg); - } -} -.animate-spin { - animation: 1s linear infinite spin; -} -.cursor-pointer { - cursor: pointer; -} -.select-none { - user-select: none; -} -.resize-none { - resize: none; -} -.list-inside { - list-style-position: inside; -} -.list-disc { - list-style-type: disc; -} -.appearance-none { - appearance: none; -} -.auto-cols-min { - grid-auto-columns: min-content; -} -.grid-flow-row { - grid-auto-flow: row; -} -.auto-rows-max { - grid-auto-rows: max-content; -} -.grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)); -} -.grid-rows-3 { - grid-template-rows: repeat(3, minmax(0, 1fr)); -} -.flex-row-reverse { - flex-direction: row-reverse; -} -.flex-wrap { - flex-wrap: wrap; -} -.place-content-start { - place-content: start; -} -.place-items-end { - place-items: end; -} -.content-center { - align-content: center; -} -.items-start { - align-items: flex-start; -} -.justify-center { - justify-content: center; -} -.justify-items-end { - justify-items: end; -} -.gap-4 { - gap: 1rem; -} -.gap-x-2 { - column-gap: 0.5rem; -} -.gap-y-3 { - row-gap: 0.75rem; -} -.space-x-4 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); -} -.space-y-3 > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 0; - margin-top: calc(0.75rem * calc(1 - var(--tw-space-y-reverse))); - margin-bottom: calc(0.75rem * var(--tw-space-y-reverse)); -} -.space-y-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-y-reverse: 1; -} -.space-x-reverse > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 1; -} -.divide-x-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(0px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(0px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-x-reverse: 0; - border-inline-end-width: calc(2px * var(--tw-divide-x-reverse)); - border-inline-start-width: calc(2px * calc(1 - var(--tw-divide-x-reverse))); -} -.divide-y-0 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(0px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(0px * var(--tw-divide-y-reverse)); -} -.divide-y-4 > :not([hidden]) ~ :not([hidden]) { - --tw-divide-y-reverse: 0; - border-top-width: calc(4px * calc(1 - var(--tw-divide-y-reverse))); - border-bottom-width: calc(4px * var(--tw-divide-y-reverse)); -} -.divide-dotted > :not([hidden]) ~ :not([hidden]) { - border-style: dotted; -} -.divide-gray-200 > :not([hidden]) ~ :not([hidden]) { - border-color: #e5e7eb; -} -.place-self-center { - place-self: center; -} -.self-end { - align-self: flex-end; -} -.justify-self-start { - justify-self: start; -} -.overflow-hidden { - overflow: hidden; -} -.overscroll-contain { - overscroll-behavior: contain; -} -.scroll-smooth { - scroll-behavior: smooth; -} -.truncate { - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} -.overflow-ellipsis { - text-overflow: ellipsis; -} -.whitespace-nowrap { - white-space: nowrap; -} -.break-words { - overflow-wrap: break-word; -} -.rounded-md { - border-radius: 0.375rem; -} -.border { - border-width: 1px; -} -.border-2 { - border-width: 2px; -} -.border-solid { - border-style: solid; -} -.border-black { - border-color: #000; -} -.bg-green-500 { - background-color: #22c55e; -} -.bg-gradient-to-r { - background-image: linear-gradient(to right, var(--tw-gradient-stops)); -} -.from-red-300 { - --tw-gradient-from: #fca5a5 var(--tw-gradient-from-position); - --tw-gradient-to: #fca5a500 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), var(--tw-gradient-to); -} -.via-purple-200 { - --tw-gradient-to: #e9d5ff00 var(--tw-gradient-to-position); - --tw-gradient-stops: var(--tw-gradient-from), #e9d5ff var(--tw-gradient-via-position), - var(--tw-gradient-to); -} -.to-blue-400 { - --tw-gradient-to: #60a5fa var(--tw-gradient-to-position); -} -.decoration-slice { - -webkit-box-decoration-break: slice; - box-decoration-break: slice; -} -.decoration-clone { - -webkit-box-decoration-break: clone; - box-decoration-break: clone; -} -.bg-cover { - background-size: cover; -} -.bg-local { - background-attachment: local; -} -.bg-clip-border { - background-clip: border-box; -} -.bg-top { - background-position: top; -} -.bg-no-repeat { - background-repeat: no-repeat; -} -.bg-origin-border { - background-origin: border-box; -} -.bg-origin-padding { - background-origin: padding-box; -} -.bg-origin-content { - background-origin: content-box; -} -.fill-current { - fill: currentColor; -} -.stroke-current { - stroke: currentColor; -} -.stroke-2 { - stroke-width: 2px; -} -.object-cover { - object-fit: cover; -} -.object-bottom { - object-position: bottom; -} -.p-4 { - padding: 1rem; -} -.px-3 { - padding-left: 0.75rem; - padding-right: 0.75rem; -} -.py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; -} -.pb-3 { - padding-bottom: 0.75rem; -} -.pl-4 { - padding-left: 1rem; -} -.pr-2 { - padding-right: 0.5rem; -} -.pt-1 { - padding-top: 0.25rem; -} -.text-center { - text-align: center; -} -.align-middle { - vertical-align: middle; -} -.font-sans { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, - Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, - Noto Color Emoji; -} -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} -.font-medium { - font-weight: 500; -} -.uppercase { - text-transform: uppercase; -} -.not-italic { - font-style: normal; -} -.ordinal { - --tw-ordinal: ordinal; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.tabular-nums { - --tw-numeric-spacing: tabular-nums; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.diagonal-fractions { - --tw-numeric-fraction: diagonal-fractions; - font-variant-numeric: var(--tw-ordinal) var(--tw-slashed-zero) var(--tw-numeric-figure) - var(--tw-numeric-spacing) var(--tw-numeric-fraction); -} -.leading-5 { - line-height: 1.25rem; -} -.leading-relaxed { - line-height: 1.625; -} -.tracking-tight { - letter-spacing: -0.025em; -} -.text-indigo-500 { - color: #6366f1; -} -.underline { - text-decoration-line: underline; -} -.antialiased { - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} -.placeholder-green-300::placeholder { - color: #86efac; -} -.opacity-90 { - opacity: 0.9; -} -.bg-blend-darken { - background-blend-mode: darken; -} -.bg-blend-difference { - background-blend-mode: difference; -} -.mix-blend-multiply { - mix-blend-mode: multiply; -} -.mix-blend-saturation { - mix-blend-mode: saturation; -} -.shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-lg { - --tw-shadow: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; - --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), - 0 4px 6px -4px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.ring { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(3px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-4 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); -} -.ring-white { - --tw-ring-color: #fff; -} -.ring-offset-2 { - --tw-ring-offset-width: 2px; -} -.ring-offset-blue-300 { - --tw-ring-offset-color: #93c5fd; -} -.blur-md { - --tw-blur: blur(12px); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.brightness-150 { - --tw-brightness: brightness(1.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.contrast-50 { - --tw-contrast: contrast(0.5); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.drop-shadow-md { - --tw-drop-shadow: drop-shadow(0 4px 3px #00000012) drop-shadow(0 2px 2px #0000000f); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.grayscale { - --tw-grayscale: grayscale(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.hue-rotate-60 { - --tw-hue-rotate: hue-rotate(60deg); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.invert { - --tw-invert: invert(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.saturate-200 { - --tw-saturate: saturate(2); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.sepia { - --tw-sepia: sepia(100%); - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter { - filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) - var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); -} -.filter-none { - filter: none; -} -.backdrop-blur-lg { - --tw-backdrop-blur: blur(16px); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-brightness-50 { - --tw-backdrop-brightness: brightness(0.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-contrast-0 { - --tw-backdrop-contrast: contrast(0); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-grayscale { - --tw-backdrop-grayscale: grayscale(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-hue-rotate-90 { - --tw-backdrop-hue-rotate: hue-rotate(90deg); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-invert { - --tw-backdrop-invert: invert(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-opacity-75 { - --tw-backdrop-opacity: opacity(0.75); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-saturate-150 { - --tw-backdrop-saturate: saturate(1.5); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-sepia { - --tw-backdrop-sepia: sepia(100%); - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter { - backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) - var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) - var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); -} -.backdrop-filter-none { - backdrop-filter: none; -} -.transition { - transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.transition-all { - transition-property: all; - transition-duration: 0.15s; - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} -.delay-300 { - transition-delay: 0.3s; -} -.duration-200 { - transition-duration: 0.2s; -} -.ease-in-out { - transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); -} diff --git a/tests/raw-content.test.js b/tests/raw-content.test.js index 417c37485..a55e373fb 100644 --- a/tests/raw-content.test.js +++ b/tests/raw-content.test.js @@ -1,173 +1,164 @@ import fs from 'fs' import path from 'path' -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('raw content', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- -
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +it('raw content', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './raw-content.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './raw-content.oxide.test.css'), 'utf8') - ) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './raw-content.test.css'), 'utf8') + ) }) }) diff --git a/tests/relative-purge-paths.test.js b/tests/relative-purge-paths.test.js index 95fbe7bad..0e7e5feed 100644 --- a/tests/relative-purge-paths.test.js +++ b/tests/relative-purge-paths.test.js @@ -1,24 +1,22 @@ -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(() => { - test('relative purge paths', () => { - let config = { - content: ['./tests/relative-purge-paths.test.html'], - corePlugins: { preflight: false }, - } +test('relative purge paths', () => { + let config = { + content: ['./tests/relative-purge-paths.test.html'], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toIncludeCss(css` - .font-bold { - font-weight: 700; - } - `) - }) + return run(input, config).then((result) => { + expect(result.css).toIncludeCss(css` + .font-bold { + font-weight: 700; + } + `) }) }) diff --git a/tests/resolve-defaults-at-rules.test.js b/tests/resolve-defaults-at-rules.test.js index 5c7e0738e..1d80c780b 100644 --- a/tests/resolve-defaults-at-rules.test.js +++ b/tests/resolve-defaults-at-rules.test.js @@ -1,774 +1,771 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('basic utilities', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } +test('basic utilities', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .skew-y-6 { - --tw-skew-y: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .scale-x-110 { - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with pseudo-class variants', async () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .hover\:scale-x-110:hover { - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .focus\:rotate-3:focus { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .hover\:focus\:skew-y-6:focus:hover { - --tw-skew-y: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with pseudo-element variants', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .before\:scale-x-110:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .after\:rotate-3:after { - content: var(--tw-content); - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with multi-class variants', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .group:hover .group-hover\:scale-x-110 { - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .peer:focus ~ .peer-focus\:rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with multi-class pseudo-element variants', async () => { - let config = { - content: [ - { raw: html`
` }, - ], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .group:hover .group-hover\:before\:scale-x-110:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .peer:focus ~ .peer-focus\:after\:rotate-3:after { - content: var(--tw-content); - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with multi-class pseudo-element and pseudo-class variants', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .group:hover .group-hover\:hover\:before\:scale-x-110:hover:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .peer:focus ~ .peer-focus\:focus\:after\:rotate-3:focus:after { - content: var(--tw-content); - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('with apply', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - - @layer utilities { - .foo { - @apply rotate-3; - } + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; } - - .bar { - @apply before:scale-110; + .rotate-3 { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - - .baz::before { - @apply rotate-45; + .skew-y-6 { + --tw-skew-y: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } + .scale-x-110 { + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) +test('with pseudo-class variants', async () => { + let config = { + content: [ + { raw: html`
` }, + ], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .hover\:scale-x-110:hover { + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .focus\:rotate-3:focus { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .hover\:focus\:skew-y-6:focus:hover { + --tw-skew-y: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with pseudo-element variants', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .before\:scale-x-110:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .after\:rotate-3:after { + content: var(--tw-content); + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with multi-class variants', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .group:hover .group-hover\:scale-x-110 { + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .peer:focus ~ .peer-focus\:rotate-3 { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with multi-class pseudo-element variants', async () => { + let config = { + content: [ + { raw: html`
` }, + ], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .group:hover .group-hover\:before\:scale-x-110:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .peer:focus ~ .peer-focus\:after\:rotate-3:after { + content: var(--tw-content); + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with multi-class pseudo-element and pseudo-class variants', async () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .group:hover .group-hover\:hover\:before\:scale-x-110:hover:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .peer:focus ~ .peer-focus\:focus\:after\:rotate-3:focus:after { + content: var(--tw-content); + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('with apply', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + + @layer utilities { + .foo { + @apply rotate-3; + } + } + + .bar { + @apply before:scale-110; + } + + .baz::before { + @apply rotate-45; + } + + .whats ~ .next > span:hover { + @apply skew-x-6; + } + + .media-queries { + @apply md:rotate-45; + } + + .a, + .b, + .c { + @apply skew-y-3; + } + + .a, + .b { + @apply rotate-45; + } + + .a::before, + .b::after { + @apply rotate-90; + } + + .recursive { + @apply foo; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + .foo { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .bar:before { + content: var(--tw-content); + --tw-scale-x: 1.1; + --tw-scale-y: 1.1; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .baz:before { + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } .whats ~ .next > span:hover { - @apply skew-x-6; + --tw-skew-x: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - - .media-queries { - @apply md:rotate-45; + @media (min-width: 768px) { + .media-queries { + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) + rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) + scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); + } } - .a, .b, .c { - @apply skew-y-3; + --tw-skew-y: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - .a, .b { - @apply rotate-45; + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - - .a::before, - .b::after { - @apply rotate-90; - } - - .recursive { - @apply foo; - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .foo { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .bar:before { - content: var(--tw-content); - --tw-scale-x: 1.1; - --tw-scale-y: 1.1; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .baz:before { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .whats ~ .next > span:hover { - --tw-skew-x: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - @media (min-width: 768px) { - .media-queries { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - } - .a, - .b, - .c { - --tw-skew-y: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .a, - .b { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .a:before, - .b:after { - --tw-rotate: 90deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .recursive { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('legacy pseudo-element syntax is supported', async () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - - .a:before { - @apply rotate-45; - } - + .a:before, .b:after { - @apply rotate-3; + --tw-rotate: 90deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } - - .c:first-line { - @apply rotate-1; + .recursive { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); } + `) + }) +}) +test('legacy pseudo-element syntax is supported', async () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + + .a:before { + @apply rotate-45; + } + + .b:after { + @apply rotate-3; + } + + .c:first-line { + @apply rotate-1; + } + + .d:first-letter { + @apply rotate-6; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .a:before, + .b:after, + .c:first-line, .d:first-letter { - @apply rotate-6; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .a:before, - .b:after, - .c:first-line, - .d:first-letter { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - .a:before { - --tw-rotate: 45deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .b:after { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .c:first-line { - --tw-rotate: 1deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - .d:first-letter { - --tw-rotate: 6deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) + .a:before { + --tw-rotate: 45deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .b:after { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .c:first-line { + --tw-rotate: 1deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + .d:first-letter { + --tw-rotate: 6deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) }) +}) - test('with borders', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['borderWidth', 'borderColor', 'borderOpacity'], - } +test('with borders', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['borderWidth', 'borderColor', 'borderOpacity'], + } - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .border { - border-width: 1px; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .border { + border-width: 1px; + } + .border-red-500 { + --tw-border-opacity: 1; + border-color: rgb(239 68 68 / var(--tw-border-opacity)); + } + @media (min-width: 768px) { + .md\:border-2 { + border-width: 2px; } - .border-red-500 { - --tw-border-opacity: 1; - border-color: rgb(239 68 68 / var(--tw-border-opacity)); - } - @media (min-width: 768px) { - .md\:border-2 { - border-width: 2px; - } - } - `) - }) + } + `) }) +}) - test('with shadows', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['boxShadow', 'ringColor', 'ringWidth'], - } +test('with shadows', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['boxShadow', 'ringColor', 'ringWidth'], + } - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #3b82f680; - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - } - .shadow { - --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; - --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), - 0 1px 2px -1px var(--tw-shadow-color); + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + .shadow { + --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), + 0 1px 2px -1px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); + } + .ring-1 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) + var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) + var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); + } + .ring-black\/25 { + --tw-ring-color: #00000040; + } + @media (min-width: 768px) { + .md\:shadow-xl { + --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; + --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), + 0 8px 10px -6px var(--tw-shadow-color); box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } - .ring-1 { - --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) - var(--tw-ring-offset-color); - --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) - var(--tw-ring-color); - box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), - var(--tw-shadow, 0 0 #0000); - } - .ring-black\/25 { - --tw-ring-color: #00000040; - } - @media (min-width: 768px) { - .md\:shadow-xl { - --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; - --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), - 0 8px 10px -6px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - } - `) - }) - }) - - test('when no utilities that need the defaults are used', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['transform', 'scale', 'rotate', 'skew'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - *, - :before, - :after, - ::backdrop { - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - } - `) - }) - }) - - test('when a utility uses defaults but they do not exist', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: ['rotate'], - } - - let input = css` - @tailwind base; - /* --- */ - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .rotate-3 { - --tw-rotate: 3deg; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('selectors are reduced to the lowest possible specificity', async () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: [], - } - - let input = css` - @defaults test { - --color: black; } - - /* --- */ - - .foo { - @defaults test; - background-color: var(--color); - } - - #app { - @defaults test; - border-color: var(--color); - } - - span#page { - @defaults test; - color: var(--color); - } - - div[data-foo='bar']#other { - @defaults test; - fill: var(--color); - } - - div[data-bar='baz'] { - @defaults test; - stroke: var(--color); - } - - article { - @defaults test; - --article: var(--color); - } - - div[data-foo='bar']#another::before { - @defaults test; - fill: var(--color); - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .foo, - [id='app'], - [id='page'], - [id='other'], - [data-bar='baz'], - article, - [id='another']:before { - --color: black; - } - .foo { - background-color: var(--color); - } - #app { - border-color: var(--color); - } - span#page { - color: var(--color); - } - div[data-foo='bar']#other { - fill: var(--color); - } - div[data-bar='baz'] { - stroke: var(--color); - } - article { - --article: var(--color); - } - div[data-foo='bar']#another:before { - fill: var(--color); - } - `) - }) - }) - - test('No defaults without @tailwind base', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - // Optimize universal defaults doesn't work well with isolated modules - // We require you to use @tailwind base to inject the defaults - let input = css` - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .scale-150 { - --tw-scale-x: 1.5; - --tw-scale-y: 1.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) - }) - - test('no defaults and apply without @tailwind base', () => { - let config = { - experimental: { optimizeUniversalDefaults: true }, - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - // Optimize universal defaults doesn't work well with isolated modules - // We require you to use @tailwind base to inject the defaults - let input = css` - @tailwind components; - @tailwind utilities; - - .my-card { - @apply scale-150; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .my-card { - --tw-scale-x: 1.5; - --tw-scale-y: 1.5; - transform: translate(var(--tw-translate-x), var(--tw-translate-y)) - rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) - scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); - } - `) - }) + `) + }) +}) + +test('when no utilities that need the defaults are used', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['transform', 'scale', 'rotate', 'skew'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + *, + :before, + :after, + ::backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + `) + }) +}) + +test('when a utility uses defaults but they do not exist', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: ['rotate'], + } + + let input = css` + @tailwind base; + /* --- */ + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .rotate-3 { + --tw-rotate: 3deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('selectors are reduced to the lowest possible specificity', async () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: [], + } + + let input = css` + @defaults test { + --color: black; + } + + /* --- */ + + .foo { + @defaults test; + background-color: var(--color); + } + + #app { + @defaults test; + border-color: var(--color); + } + + span#page { + @defaults test; + color: var(--color); + } + + div[data-foo='bar']#other { + @defaults test; + fill: var(--color); + } + + div[data-bar='baz'] { + @defaults test; + stroke: var(--color); + } + + article { + @defaults test; + --article: var(--color); + } + + div[data-foo='bar']#another::before { + @defaults test; + fill: var(--color); + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .foo, + [id='app'], + [id='page'], + [id='other'], + [data-bar='baz'], + article, + [id='another']:before { + --color: black; + } + .foo { + background-color: var(--color); + } + #app { + border-color: var(--color); + } + span#page { + color: var(--color); + } + div[data-foo='bar']#other { + fill: var(--color); + } + div[data-bar='baz'] { + stroke: var(--color); + } + article { + --article: var(--color); + } + div[data-foo='bar']#another:before { + fill: var(--color); + } + `) + }) +}) + +test('No defaults without @tailwind base', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + // Optimize universal defaults doesn't work well with isolated modules + // We require you to use @tailwind base to inject the defaults + let input = css` + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .scale-150 { + --tw-scale-x: 1.5; + --tw-scale-y: 1.5; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) + }) +}) + +test('no defaults and apply without @tailwind base', () => { + let config = { + experimental: { optimizeUniversalDefaults: true }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + // Optimize universal defaults doesn't work well with isolated modules + // We require you to use @tailwind base to inject the defaults + let input = css` + @tailwind components; + @tailwind utilities; + + .my-card { + @apply scale-150; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .my-card { + --tw-scale-x: 1.5; + --tw-scale-y: 1.5; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) + skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) + scaleY(var(--tw-scale-y)); + } + `) }) }) diff --git a/tests/resolveConfig.test.js b/tests/resolveConfig.test.js index c99a986de..954c40659 100644 --- a/tests/resolveConfig.test.js +++ b/tests/resolveConfig.test.js @@ -1,1797 +1,1794 @@ import resolveConfig from '../src/util/resolveConfig' import corePluginList from '../src/corePluginList' -import { crosscheck } from './util/run' -crosscheck(() => { - test('prefix key overrides default prefix', () => { - const userConfig = { - prefix: 'tw-', - } +test('prefix key overrides default prefix', () => { + const userConfig = { + prefix: 'tw-', + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: 'tw-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: 'tw-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('important key overrides default important', () => { - const userConfig = { - important: true, - } +test('important key overrides default important', () => { + const userConfig = { + important: true, + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '', - important: true, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '', + important: true, + separator: ':', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('important (selector) key overrides default important', () => { - const userConfig = { - important: '#app', - } +test('important (selector) key overrides default important', () => { + const userConfig = { + important: '#app', + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '', - important: '#app', - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '', + important: '#app', + separator: ':', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('separator key overrides default separator', () => { - const userConfig = { - separator: '__', - } +test('separator key overrides default separator', () => { + const userConfig = { + separator: '__', + } - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: '__', - theme: { - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: '__', + theme: { + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('theme key is merged instead of replaced', () => { - const userConfig = { - theme: { - screens: { - mobile: '400px', - }, +test('theme key is merged instead of replaced', () => { + const userConfig = { + theme: { + screens: { + mobile: '400px', }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - 'grey-darker': '#606f7b', - 'grey-dark': '#8795a1', - grey: '#b8c2cc', - 'grey-light': '#dae1e7', - 'grey-lighter': '#f1f5f8', - }, - fonts: { - sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], - serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], - }, - screens: { - sm: '500px', - md: '750px', - lg: '1000px', - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + 'grey-darker': '#606f7b', + 'grey-dark': '#8795a1', + grey: '#b8c2cc', + 'grey-light': '#dae1e7', + 'grey-lighter': '#f1f5f8', }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - 'grey-darker': '#606f7b', - 'grey-dark': '#8795a1', - grey: '#b8c2cc', - 'grey-light': '#dae1e7', - 'grey-lighter': '#f1f5f8', - }, - fonts: { - sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], - serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], - }, - screens: { - mobile: '400px', - }, + fonts: { + sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], + serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], }, - }) + screens: { + sm: '500px', + md: '750px', + lg: '1000px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + 'grey-darker': '#606f7b', + 'grey-dark': '#8795a1', + grey: '#b8c2cc', + 'grey-light': '#dae1e7', + 'grey-lighter': '#f1f5f8', + }, + fonts: { + sans: ['system-ui', 'BlinkMacSystemFont', '-apple-system', 'Roboto', 'sans-serif'], + serif: ['Constantia', 'Lucida Bright', 'Georgia', 'serif'], + }, + screens: { + mobile: '400px', + }, + }, }) +}) - test('theme key is deeply merged instead of replaced', () => { - const userConfig = { - theme: { - extend: { - colors: { - grey: { - darker: '#606f7b', - dark: '#8795a1', - }, - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - grey: { - grey: '#b8c2cc', - light: '#dae1e7', - lighter: '#f1f5f8', - }, - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { +test('theme key is deeply merged instead of replaced', () => { + const userConfig = { + theme: { + extend: { colors: { grey: { darker: '#606f7b', dark: '#8795a1', - grey: '#b8c2cc', - light: '#dae1e7', - lighter: '#f1f5f8', }, }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + grey: { + grey: '#b8c2cc', + light: '#dae1e7', + lighter: '#f1f5f8', + }, + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + grey: { + darker: '#606f7b', + dark: '#8795a1', + grey: '#b8c2cc', + light: '#dae1e7', + lighter: '#f1f5f8', + }, + }, + }, }) +}) - test('missing top level keys are pulled from the default config', () => { - const userConfig = {} +test('missing top level keys are pulled from the default config', () => { + const userConfig = {} - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { green: '#00ff00' }, - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { green: '#00ff00' }, + screens: { + mobile: '400px', }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { green: '#00ff00' }, - screens: { - mobile: '400px', - }, + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { green: '#00ff00' }, + screens: { + mobile: '400px', }, - }) + }, }) +}) - test('functions in the default theme section are lazily evaluated', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, +test('functions in the default theme section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - backgroundColors: (theme) => theme('colors'), - textColors: (theme) => theme('colors'), + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', }, - } + backgroundColors: (theme) => theme('colors'), + textColors: (theme) => theme('colors'), + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - textColors: { - red: 'red', - green: 'green', - blue: 'blue', - }, + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - }) + backgroundColors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + textColors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + }, }) +}) - test('functions in the user theme section are lazily evaluated', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: (theme) => ({ - ...theme('colors'), - customBackground: '#bada55', - }), - textColors: (theme) => ({ - ...theme('colors'), - customText: '#facade', - }), +test('functions in the user theme section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - } + backgroundColors: (theme) => ({ + ...theme('colors'), + customBackground: '#bada55', + }), + textColors: (theme) => ({ + ...theme('colors'), + customText: '#facade', + }), + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - backgroundColors: ({ colors }) => colors, - textColors: ({ colors }) => colors, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', }, - } + backgroundColors: ({ colors }) => colors, + textColors: ({ colors }) => colors, + }, + } - const result = resolveConfig([userConfig, defaultConfig]) + const result = resolveConfig([userConfig, defaultConfig]) - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: { - red: 'red', - green: 'green', - blue: 'blue', - customBackground: '#bada55', - }, - textColors: { - red: 'red', - green: 'green', - blue: 'blue', - customText: '#facade', - }, + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - }) + backgroundColors: { + red: 'red', + green: 'green', + blue: 'blue', + customBackground: '#bada55', + }, + textColors: { + red: 'red', + green: 'green', + blue: 'blue', + customText: '#facade', + }, + }, }) +}) - test('theme values in the extend section extend the existing theme', () => { - const userConfig = { - theme: { - extend: { - opacity: { - 25: '25', - 75: '.75', - }, - backgroundColors: { - customBackground: '#bada55', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, +test('theme values in the extend section extend the existing theme', () => { + const userConfig = { + theme: { + extend: { opacity: { - 0: '0', - 50: '.5', - 100: '1', - }, - backgroundColors: (theme) => theme('colors'), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - opacity: { - 0: '0', - 50: '.5', - 100: '1', 25: '25', 75: '.75', }, backgroundColors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', customBackground: '#bada55', }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + opacity: { + 0: '0', + 50: '.5', + 100: '1', + }, + backgroundColors: (theme) => theme('colors'), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + opacity: { + 0: '0', + 50: '.5', + 100: '1', + 25: '25', + 75: '.75', + }, + backgroundColors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + customBackground: '#bada55', + }, + }, }) +}) - test('theme values in the extend section extend the user theme', () => { - const userConfig = { - theme: { - opacity: { - 0: '0', - 20: '.2', - 40: '.4', - }, - height: (theme) => theme('width'), - extend: { - opacity: { - 60: '.6', - 80: '.8', - 100: '1', - }, - height: { - customHeight: '500vh', - }, - }, +test('theme values in the extend section extend the user theme', () => { + const userConfig = { + theme: { + opacity: { + 0: '0', + 20: '.2', + 40: '.4', }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + height: (theme) => theme('width'), + extend: { opacity: { - 0: '0', - 50: '.5', - 100: '1', - }, - height: { - 0: 0, - full: '100%', - }, - width: { - 0: 0, - 1: '.25rem', - 2: '.5rem', - 3: '.75rem', - 4: '1rem', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - opacity: { - 0: '0', - 20: '.2', - 40: '.4', 60: '.6', 80: '.8', 100: '1', }, height: { - 0: 0, - 1: '.25rem', - 2: '.5rem', - 3: '.75rem', - 4: '1rem', customHeight: '500vh', }, - width: { - 0: 0, - 1: '.25rem', - 2: '.5rem', - 3: '.75rem', - 4: '1rem', - }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + opacity: { + 0: '0', + 50: '.5', + 100: '1', + }, + height: { + 0: 0, + full: '100%', + }, + width: { + 0: 0, + 1: '.25rem', + 2: '.5rem', + 3: '.75rem', + 4: '1rem', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + opacity: { + 0: '0', + 20: '.2', + 40: '.4', + 60: '.6', + 80: '.8', + 100: '1', + }, + height: { + 0: 0, + 1: '.25rem', + 2: '.5rem', + 3: '.75rem', + 4: '1rem', + customHeight: '500vh', + }, + width: { + 0: 0, + 1: '.25rem', + 2: '.5rem', + 3: '.75rem', + 4: '1rem', + }, + }, }) +}) - test('theme values in the extend section can extend values that are depended on lazily', () => { - const userConfig = { - theme: { - extend: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - backgroundColors: { - customBackground: '#bada55', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { +test('theme values in the extend section can extend values that are depended on lazily', () => { + const userConfig = { + theme: { + extend: { colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - backgroundColors: (theme) => theme('colors'), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', red: 'red', green: 'green', blue: 'blue', }, backgroundColors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - red: 'red', - green: 'green', - blue: 'blue', customBackground: '#bada55', }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + backgroundColors: (theme) => theme('colors'), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + red: 'red', + green: 'green', + blue: 'blue', + }, + backgroundColors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + red: 'red', + green: 'green', + blue: 'blue', + customBackground: '#bada55', + }, + }, }) +}) - test('theme values in the extend section are not deeply merged when they are simple arrays', () => { - const userConfig = { - theme: { - extend: { - fonts: { - sans: ['Comic Sans'], - serif: ['Papyrus', { fontFeatureSettings: '"cv11"' }], - mono: [['Lobster', 'Papyrus'], { fontFeatureSettings: '"cv11"' }], - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - fonts: { - sans: ['system-ui', 'Helvetica Neue', 'sans-serif'], - serif: ['Constantia', 'Georgia', 'serif'], - mono: ['Menlo', 'Courier New', 'monospace'], - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { +test('theme values in the extend section are not deeply merged when they are simple arrays', () => { + const userConfig = { + theme: { + extend: { fonts: { sans: ['Comic Sans'], serif: ['Papyrus', { fontFeatureSettings: '"cv11"' }], mono: [['Lobster', 'Papyrus'], { fontFeatureSettings: '"cv11"' }], }, }, - }) - }) + }, + } - test('theme values in the extend section are deeply merged, when they are arrays of objects', () => { - const userConfig = { - theme: { - extend: { - typography: { - ArrayArray: { - css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], - }, - ObjectArray: { - css: { a: { backgroundColor: 'red' } }, - }, - ArrayObject: { - css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], - }, - }, - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + fonts: { + sans: ['system-ui', 'Helvetica Neue', 'sans-serif'], + serif: ['Constantia', 'Georgia', 'serif'], + mono: ['Menlo', 'Courier New', 'monospace'], }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + fonts: { + sans: ['Comic Sans'], + serif: ['Papyrus', { fontFeatureSettings: '"cv11"' }], + mono: [['Lobster', 'Papyrus'], { fontFeatureSettings: '"cv11"' }], + }, + }, + }) +}) + +test('theme values in the extend section are deeply merged, when they are arrays of objects', () => { + const userConfig = { + theme: { + extend: { typography: { ArrayArray: { - css: [{ a: { underline: 'none' } }], + css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], }, ObjectArray: { - css: [{ a: { underline: 'none' } }], + css: { a: { backgroundColor: 'red' } }, }, ArrayObject: { - css: { a: { underline: 'none' } }, + css: [{ a: { backgroundColor: 'red' } }, { a: { color: 'green' } }], }, }, }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - typography: { - ArrayArray: { - css: [ - { a: { underline: 'none' } }, - { a: { backgroundColor: 'red' } }, - { a: { color: 'green' } }, - ], - }, - ObjectArray: { - css: [{ a: { underline: 'none' } }, { a: { backgroundColor: 'red' } }], - }, - ArrayObject: { - css: [ - { a: { underline: 'none' } }, - { a: { backgroundColor: 'red' } }, - { a: { color: 'green' } }, - ], - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + typography: { + ArrayArray: { + css: [{ a: { underline: 'none' } }], + }, + ObjectArray: { + css: [{ a: { underline: 'none' } }], + }, + ArrayObject: { + css: { a: { underline: 'none' } }, }, }, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + typography: { + ArrayArray: { + css: [ + { a: { underline: 'none' } }, + { a: { backgroundColor: 'red' } }, + { a: { color: 'green' } }, + ], + }, + ObjectArray: { + css: [{ a: { underline: 'none' } }, { a: { backgroundColor: 'red' } }], + }, + ArrayObject: { + css: [ + { a: { underline: 'none' } }, + { a: { backgroundColor: 'red' } }, + { a: { color: 'green' } }, + ], + }, + }, + }, }) +}) - test('the theme function can use a default value if the key is missing', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, +test('the theme function can use a default value if the key is missing', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', }, - } + }, + } - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + borderColor: (theme) => ({ + default: theme('colors.gray', 'currentColor'), + ...theme('colors'), + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + borderColor: { + default: 'currentColor', + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + }) +}) + +test('the theme function can resolve function values', () => { + const userConfig = { + theme: { + textColor: (theme) => ({ + lime: 'lime', + ...theme('colors'), + }), + backgroundColor: (theme) => ({ + orange: 'orange', + ...theme('textColor'), + }), + borderColor: (theme) => theme('backgroundColor'), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + textColor: { + lime: 'lime', + red: 'red', + green: 'green', + blue: 'blue', + }, + backgroundColor: { + lime: 'lime', + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + borderColor: { + lime: 'lime', + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + }, + }) +}) + +test('the theme function can resolve deep function values', () => { + const userConfig = { + theme: { + minWidth: (theme) => ({ + '1/3': theme('width.1/3'), + }), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + spacing: { + 0: '0', + }, + width: (theme) => ({ + ...theme('spacing'), + '1/3': '33.33333%', + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + spacing: { + 0: '0', + }, + width: { + 0: '0', + '1/3': '33.33333%', + }, + minWidth: { + '1/3': '33.33333%', + }, + }, + }) +}) + +test('theme values in the extend section are lazily evaluated', () => { + const userConfig = { + theme: { + colors: { + red: 'red', + green: 'green', + blue: 'blue', + }, + extend: { colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', + orange: 'orange', }, borderColor: (theme) => ({ - default: theme('colors.gray', 'currentColor'), - ...theme('colors'), + foo: theme('colors.orange'), + bar: theme('colors.red'), }), }, - } + }, + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - borderColor: { - default: 'currentColor', - red: 'red', - green: 'green', - blue: 'blue', - }, + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', }, - }) + borderColor: (theme) => ({ + default: theme('colors.yellow', 'currentColor'), + ...theme('colors'), + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + colors: { + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + borderColor: { + default: 'currentColor', + foo: 'orange', + bar: 'red', + orange: 'orange', + red: 'red', + green: 'green', + blue: 'blue', + }, + }, }) +}) - test('the theme function can resolve function values', () => { - const userConfig = { - theme: { - textColor: (theme) => ({ - lime: 'lime', - ...theme('colors'), +test('lazily evaluated values have access to the config utils', () => { + const userConfig = { + theme: { + inset: (theme) => theme('margin'), + shift: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), + }), + extend: { + nudge: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), }), - backgroundColor: (theme) => ({ + }, + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + spacing: { + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + margin: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), + }), + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + spacing: { + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + inset: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + margin: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + shift: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + nudge: { + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + }, + }) +}) + +test('the original theme is not mutated', () => { + const userConfig = { + theme: { + extend: { + colors: { orange: 'orange', - ...theme('textColor'), + }, + }, + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + colors: { + cyan: 'cyan', + magenta: 'magenta', + yellow: 'yellow', + }, + }, + } + + resolveConfig([userConfig, defaultConfig]) + + expect(userConfig).toEqual({ + theme: { + extend: { + colors: { + orange: 'orange', + }, + }, + }, + }) +}) + +test('custom properties are multiplied by -1 for negative values', () => { + const userConfig = { + theme: { + spacing: { + 0: 0, + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + auto: 'auto', + foo: 'var(--foo)', + bar: 'var(--bar, 500px)', + baz: 'calc(50% - 10px)', + qux: '10poops', + }, + margin: (theme, { negative }) => ({ + ...theme('spacing'), + ...negative(theme('spacing')), + }), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: {}, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result.theme.spacing).toEqual({ + 0: 0, + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + auto: 'auto', + foo: 'var(--foo)', + bar: 'var(--bar, 500px)', + baz: 'calc(50% - 10px)', + qux: '10poops', + }) + expect(result.theme.margin).toEqual({ + 0: 0, + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + auto: 'auto', + foo: 'var(--foo)', + bar: 'var(--bar, 500px)', + baz: 'calc(50% - 10px)', + qux: '10poops', + '-0': '0', + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + '-foo': 'calc(var(--foo) * -1)', + '-bar': 'calc(var(--bar, 500px) * -1)', + '-baz': 'calc(calc(50% - 10px) * -1)', + '-qux': '-10poops', + }) +}) + +test('more than two config objects can be resolved', () => { + const firstConfig = { + theme: { + extend: { + fontFamily: () => ({ + code: ['Menlo', 'monospace'], }), - borderColor: (theme) => theme('backgroundColor'), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { colors: { red: 'red', - green: 'green', - blue: 'blue', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - textColor: { - lime: 'lime', - red: 'red', - green: 'green', - blue: 'blue', }, backgroundColor: { - lime: 'lime', + customBackgroundOne: '#bada55', + }, + textDecorationColor: { orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', - }, - borderColor: { - lime: 'lime', - orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', }, }, - }) - }) + }, + } - test('the theme function can resolve deep function values', () => { - const userConfig = { - theme: { - minWidth: (theme) => ({ - '1/3': theme('width.1/3'), - }), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - spacing: { - 0: '0', - }, - width: (theme) => ({ - ...theme('spacing'), - '1/3': '33.33333%', - }), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - spacing: { - 0: '0', - }, - width: { - 0: '0', - '1/3': '33.33333%', - }, - minWidth: { - '1/3': '33.33333%', - }, - }, - }) - }) - - test('theme values in the extend section are lazily evaluated', () => { - const userConfig = { - theme: { - colors: { - red: 'red', - green: 'green', - blue: 'blue', - }, - extend: { - colors: { - orange: 'orange', - }, - borderColor: (theme) => ({ - foo: theme('colors.orange'), - bar: theme('colors.red'), - }), - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - borderColor: (theme) => ({ - default: theme('colors.yellow', 'currentColor'), - ...theme('colors'), - }), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - colors: { - orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', - }, - borderColor: { - default: 'currentColor', - foo: 'orange', - bar: 'red', - orange: 'orange', - red: 'red', - green: 'green', - blue: 'blue', - }, - }, - }) - }) - - test('lazily evaluated values have access to the config utils', () => { - const userConfig = { - theme: { - inset: (theme) => theme('margin'), - shift: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - extend: { - nudge: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - spacing: { - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - margin: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - spacing: { - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - inset: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - margin: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - shift: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - nudge: { - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - }, - }) - }) - - test('the original theme is not mutated', () => { - const userConfig = { - theme: { - extend: { - colors: { - orange: 'orange', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - colors: { - cyan: 'cyan', - magenta: 'magenta', - yellow: 'yellow', - }, - }, - } - - resolveConfig([userConfig, defaultConfig]) - - expect(userConfig).toEqual({ - theme: { - extend: { - colors: { - orange: 'orange', - }, - }, - }, - }) - }) - - test('custom properties are multiplied by -1 for negative values', () => { - const userConfig = { - theme: { - spacing: { - 0: 0, - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - auto: 'auto', - foo: 'var(--foo)', - bar: 'var(--bar, 500px)', - baz: 'calc(50% - 10px)', - qux: '10poops', - }, - margin: (theme, { negative }) => ({ - ...theme('spacing'), - ...negative(theme('spacing')), - }), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: {}, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result.theme.spacing).toEqual({ - 0: 0, - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - auto: 'auto', - foo: 'var(--foo)', - bar: 'var(--bar, 500px)', - baz: 'calc(50% - 10px)', - qux: '10poops', - }) - expect(result.theme.margin).toEqual({ - 0: 0, - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - auto: 'auto', - foo: 'var(--foo)', - bar: 'var(--bar, 500px)', - baz: 'calc(50% - 10px)', - qux: '10poops', - '-0': '0', - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - '-foo': 'calc(var(--foo) * -1)', - '-bar': 'calc(var(--bar, 500px) * -1)', - '-baz': 'calc(calc(50% - 10px) * -1)', - '-qux': '-10poops', - }) - }) - - test('more than two config objects can be resolved', () => { - const firstConfig = { - theme: { - extend: { - fontFamily: () => ({ - code: ['Menlo', 'monospace'], - }), - colors: { - red: 'red', - }, - backgroundColor: { - customBackgroundOne: '#bada55', - }, - textDecorationColor: { - orange: 'orange', - }, - }, - }, - } - - const secondConfig = { - prefix: '-', - important: false, - separator: ':', - theme: { - extend: { - fontFamily: { - quote: ['Helvetica', 'serif'], - }, - colors: { - green: 'green', - }, - backgroundColor: { - customBackgroundTwo: '#facade', - }, - textDecorationColor: (theme) => theme('colors'), - }, - }, - } - - const thirdConfig = { - prefix: '-', - important: false, - separator: ':', - theme: { - extend: { - fontFamily: { - hero: ['Futura', 'sans-serif'], - }, - colors: { - pink: 'pink', - }, - backgroundColor: () => ({ - customBackgroundThree: '#c0ffee', - }), - textDecorationColor: { - lime: 'lime', - }, - }, - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { + const secondConfig = { + prefix: '-', + important: false, + separator: ':', + theme: { + extend: { fontFamily: { - body: ['Arial', 'sans-serif'], - display: ['Georgia', 'serif'], - }, - colors: { - blue: 'blue', - }, - backgroundColor: (theme) => theme('colors'), - }, - } - - const result = resolveConfig([firstConfig, secondConfig, thirdConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - fontFamily: { - body: ['Arial', 'sans-serif'], - display: ['Georgia', 'serif'], - code: ['Menlo', 'monospace'], quote: ['Helvetica', 'serif'], + }, + colors: { + green: 'green', + }, + backgroundColor: { + customBackgroundTwo: '#facade', + }, + textDecorationColor: (theme) => theme('colors'), + }, + }, + } + + const thirdConfig = { + prefix: '-', + important: false, + separator: ':', + theme: { + extend: { + fontFamily: { hero: ['Futura', 'sans-serif'], }, colors: { - red: 'red', - green: 'green', - blue: 'blue', pink: 'pink', }, - backgroundColor: { - red: 'red', - green: 'green', - blue: 'blue', - pink: 'pink', - customBackgroundOne: '#bada55', - customBackgroundTwo: '#facade', + backgroundColor: () => ({ customBackgroundThree: '#c0ffee', - }, + }), textDecorationColor: { - red: 'red', - green: 'green', - blue: 'blue', - pink: 'pink', - orange: 'orange', lime: 'lime', }, }, - }) + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + fontFamily: { + body: ['Arial', 'sans-serif'], + display: ['Georgia', 'serif'], + }, + colors: { + blue: 'blue', + }, + backgroundColor: (theme) => theme('colors'), + }, + } + + const result = resolveConfig([firstConfig, secondConfig, thirdConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + fontFamily: { + body: ['Arial', 'sans-serif'], + display: ['Georgia', 'serif'], + code: ['Menlo', 'monospace'], + quote: ['Helvetica', 'serif'], + hero: ['Futura', 'sans-serif'], + }, + colors: { + red: 'red', + green: 'green', + blue: 'blue', + pink: 'pink', + }, + backgroundColor: { + red: 'red', + green: 'green', + blue: 'blue', + pink: 'pink', + customBackgroundOne: '#bada55', + customBackgroundTwo: '#facade', + customBackgroundThree: '#c0ffee', + }, + textDecorationColor: { + red: 'red', + green: 'green', + blue: 'blue', + pink: 'pink', + orange: 'orange', + lime: 'lime', + }, + }, }) +}) - test('plugin config modifications are applied', () => { - const userConfig = { - plugins: [ - { - config: { - prefix: 'tw-', - }, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', +test('plugin config modifications are applied', () => { + const userConfig = { + plugins: [ + { + config: { + prefix: 'tw-', }, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'tw-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'tw-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('user config takes precedence over plugin config modifications', () => { - const userConfig = { - prefix: 'user-', - plugins: [ - { - config: { - prefix: 'tw-', - }, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', +test('user config takes precedence over plugin config modifications', () => { + const userConfig = { + prefix: 'user-', + plugins: [ + { + config: { + prefix: 'tw-', }, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'user-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'user-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('plugin config can register plugins that also have config', () => { - const userConfig = { - plugins: [ - { - config: { - prefix: 'tw-', - plugins: [ - { - config: { - important: true, - }, +test('plugin config can register plugins that also have config', () => { + const userConfig = { + plugins: [ + { + config: { + prefix: 'tw-', + plugins: [ + { + config: { + important: true, }, - { - config: { - separator: '__', - }, + }, + { + config: { + separator: '__', }, - ], - }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', + }, + ], }, + handler() {}, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'tw-', - important: true, - separator: '__', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'tw-', + important: true, + separator: '__', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('plugin configs take precedence over plugin configs registered by that plugin', () => { - const userConfig = { - plugins: [ - { - config: { - prefix: 'outer-', - plugins: [ - { - config: { - prefix: 'inner-', - }, +test('plugin configs take precedence over plugin configs registered by that plugin', () => { + const userConfig = { + plugins: [ + { + config: { + prefix: 'outer-', + plugins: [ + { + config: { + prefix: 'inner-', }, - ], - }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - screens: { - mobile: '400px', + }, + ], }, + handler() {}, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: 'outer-', - important: false, - separator: ':', - theme: { - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + screens: { + mobile: '400px', }, - plugins: userConfig.plugins, - }) + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: 'outer-', + important: false, + separator: ':', + theme: { + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('plugin theme extensions are added even if user overrides top-level theme config', () => { - const userConfig = { - theme: { - width: { - '1px': '1px', - }, +test('plugin theme extensions are added even if user overrides top-level theme config', () => { + const userConfig = { + theme: { + width: { + '1px': '1px', }, - plugins: [ - { - config: { - theme: { - extend: { - width: { - '2px': '2px', - '3px': '3px', - }, + }, + plugins: [ + { + config: { + theme: { + extend: { + width: { + '2px': '2px', + '3px': '3px', }, }, }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { - width: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - screens: { - mobile: '400px', }, + handler() {}, }, - } + ], + } - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: { - width: { - '1px': '1px', - '2px': '2px', - '3px': '3px', - }, - screens: { - mobile: '400px', - }, + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + width: { + sm: '1rem', + md: '2rem', + lg: '3rem', }, - plugins: userConfig.plugins, - }) + screens: { + mobile: '400px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: { + width: { + '1px': '1px', + '2px': '2px', + '3px': '3px', + }, + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('user theme extensions take precedence over plugin theme extensions with the same key', () => { - const userConfig = { - theme: { - extend: { - width: { - xl: '6rem', - }, - }, - }, - plugins: [ - { - config: { - theme: { - extend: { - width: { - xl: '4rem', - }, - }, - }, - }, - handler() {}, - }, - ], - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: { +test('user theme extensions take precedence over plugin theme extensions with the same key', () => { + const userConfig = { + theme: { + extend: { width: { - sm: '1rem', - md: '2rem', - lg: '3rem', - }, - screens: { - mobile: '400px', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: { - width: { - sm: '1rem', - md: '2rem', - lg: '3rem', xl: '6rem', }, - screens: { - mobile: '400px', - }, }, - plugins: userConfig.plugins, - }) + }, + plugins: [ + { + config: { + theme: { + extend: { + width: { + xl: '4rem', + }, + }, + }, + }, + handler() {}, + }, + ], + } + + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: { + width: { + sm: '1rem', + md: '2rem', + lg: '3rem', + }, + screens: { + mobile: '400px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: { + width: { + sm: '1rem', + md: '2rem', + lg: '3rem', + xl: '6rem', + }, + screens: { + mobile: '400px', + }, + }, + plugins: userConfig.plugins, }) +}) - test('extensions are applied in the right order', () => { - const userConfig = { - theme: { - extend: { - colors: { - grey: { - light: '#eee', - }, - }, - }, - }, - } - - const otherConfig = { - theme: { - extend: { - colors: { - grey: { - light: '#ddd', - darker: '#111', - }, - }, - }, - }, - } - - const anotherConfig = { - theme: { - extend: { - colors: { - grey: { - darker: '#222', - }, - }, - }, - }, - } - - const defaultConfig = { - content: [], - theme: { - colors: { - grey: { - light: '#ccc', - dark: '#333', - }, - }, - }, - } - - const result = resolveConfig([userConfig, otherConfig, anotherConfig, defaultConfig]) - - expect(result).toMatchObject({ - theme: { +test('extensions are applied in the right order', () => { + const userConfig = { + theme: { + extend: { colors: { grey: { light: '#eee', - dark: '#333', + }, + }, + }, + }, + } + + const otherConfig = { + theme: { + extend: { + colors: { + grey: { + light: '#ddd', darker: '#111', }, }, }, - }) - }) + }, + } - test('core plugin configuration builds on the default list when starting with an empty object', () => { - const userConfig = { - corePlugins: { display: false }, - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - corePlugins: {}, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: {}, - corePlugins: corePluginList.filter((c) => c !== 'display'), - }) - }) - - test('core plugins that are disabled by default can be enabled', () => { - const userConfig = { - corePlugins: { display: true }, - } - - const defaultConfig = { - presets: [], - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - corePlugins: { display: false }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - expect(result.corePlugins).toContain('display') - }) - - test('core plugin configurations stack', () => { - const userConfig = { - corePlugins: { display: false }, - } - - const otherConfig = { - corePlugins: ({ corePlugins }) => { - return [...corePlugins, 'margin'] - }, - } - - const defaultConfig = { - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - corePlugins: ['float', 'display', 'padding'], - } - - const result = resolveConfig([userConfig, otherConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: {}, - corePlugins: ['float', 'padding', 'margin'], - }) - }) - - test('plugins are merged', () => { - const userConfig = { - plugins: ['3'], - } - - const otherConfig = { - plugins: ['2'], - } - - const defaultConfig = { - plugins: ['1'], - prefix: '', - important: false, - separator: ':', - content: [], - theme: {}, - } - - const result = resolveConfig([userConfig, otherConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '', - important: false, - separator: ':', - theme: {}, - plugins: ['1', '2', '3'], - }) - }) - - test('all helpers can be destructured from the first function argument', () => { - const userConfig = { - theme: { - example: ({ theme, colors, negative, breakpoints }) => ({ - weight: theme('fontWeight.bold'), - black: colors.black, - white: colors.white, - ...negative(theme('spacing')), - ...breakpoints(theme('screens')), - }), - }, - } - - const defaultConfig = { - prefix: '-', - important: false, - separator: ':', - content: [], - theme: { - screens: { - sm: '640px', - md: '768px', - }, - fontWeight: { - bold: 700, - }, - spacing: { - 0: '0px', - 1: '1px', - 2: '2px', - 3: '3px', - 4: '4px', - }, - }, - } - - const result = resolveConfig([userConfig, defaultConfig]) - - expect(result).toMatchObject({ - prefix: '-', - important: false, - separator: ':', - theme: { - example: { - weight: 700, - black: '#000', - white: '#fff', - '-1': '-1px', - '-2': '-2px', - '-3': '-3px', - '-4': '-4px', - 'screen-sm': '640px', - 'screen-md': '768px', - }, - }, - }) - }) - - test('does not duplicate extended configs every time resolveConfig is called', () => { - let shared = { - foo: { bar: { baz: [{ color: 'red' }] } }, - } - - const createConfig = (color) => - resolveConfig([ - { - theme: { - foo: shared.foo, - extend: { - foo: { bar: { baz: { color } } }, - }, + const anotherConfig = { + theme: { + extend: { + colors: { + grey: { + darker: '#222', }, }, - ]) + }, + }, + } - createConfig('orange') - createConfig('yellow') - createConfig('green') + const defaultConfig = { + content: [], + theme: { + colors: { + grey: { + light: '#ccc', + dark: '#333', + }, + }, + }, + } - const result = createConfig('blue') + const result = resolveConfig([userConfig, otherConfig, anotherConfig, defaultConfig]) - expect(shared.foo.bar.baz).toMatchObject([{ color: 'red' }]) - expect(result.theme.foo.bar.baz).toMatchObject([{ color: 'red' }, { color: 'blue' }]) + expect(result).toMatchObject({ + theme: { + colors: { + grey: { + light: '#eee', + dark: '#333', + darker: '#111', + }, + }, + }, }) }) + +test('core plugin configuration builds on the default list when starting with an empty object', () => { + const userConfig = { + corePlugins: { display: false }, + } + + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + corePlugins: {}, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: {}, + corePlugins: corePluginList.filter((c) => c !== 'display'), + }) +}) + +test('core plugins that are disabled by default can be enabled', () => { + const userConfig = { + corePlugins: { display: true }, + } + + const defaultConfig = { + presets: [], + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + corePlugins: { display: false }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + expect(result.corePlugins).toContain('display') +}) + +test('core plugin configurations stack', () => { + const userConfig = { + corePlugins: { display: false }, + } + + const otherConfig = { + corePlugins: ({ corePlugins }) => { + return [...corePlugins, 'margin'] + }, + } + + const defaultConfig = { + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + corePlugins: ['float', 'display', 'padding'], + } + + const result = resolveConfig([userConfig, otherConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: {}, + corePlugins: ['float', 'padding', 'margin'], + }) +}) + +test('plugins are merged', () => { + const userConfig = { + plugins: ['3'], + } + + const otherConfig = { + plugins: ['2'], + } + + const defaultConfig = { + plugins: ['1'], + prefix: '', + important: false, + separator: ':', + content: [], + theme: {}, + } + + const result = resolveConfig([userConfig, otherConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '', + important: false, + separator: ':', + theme: {}, + plugins: ['1', '2', '3'], + }) +}) + +test('all helpers can be destructured from the first function argument', () => { + const userConfig = { + theme: { + example: ({ theme, colors, negative, breakpoints }) => ({ + weight: theme('fontWeight.bold'), + black: colors.black, + white: colors.white, + ...negative(theme('spacing')), + ...breakpoints(theme('screens')), + }), + }, + } + + const defaultConfig = { + prefix: '-', + important: false, + separator: ':', + content: [], + theme: { + screens: { + sm: '640px', + md: '768px', + }, + fontWeight: { + bold: 700, + }, + spacing: { + 0: '0px', + 1: '1px', + 2: '2px', + 3: '3px', + 4: '4px', + }, + }, + } + + const result = resolveConfig([userConfig, defaultConfig]) + + expect(result).toMatchObject({ + prefix: '-', + important: false, + separator: ':', + theme: { + example: { + weight: 700, + black: '#000', + white: '#fff', + '-1': '-1px', + '-2': '-2px', + '-3': '-3px', + '-4': '-4px', + 'screen-sm': '640px', + 'screen-md': '768px', + }, + }, + }) +}) + +test('does not duplicate extended configs every time resolveConfig is called', () => { + let shared = { + foo: { bar: { baz: [{ color: 'red' }] } }, + } + + const createConfig = (color) => + resolveConfig([ + { + theme: { + foo: shared.foo, + extend: { + foo: { bar: { baz: { color } } }, + }, + }, + }, + ]) + + createConfig('orange') + createConfig('yellow') + createConfig('green') + + const result = createConfig('blue') + + expect(shared.foo.bar.baz).toMatchObject([{ color: 'red' }]) + expect(result.theme.foo.bar.baz).toMatchObject([{ color: 'red' }, { color: 'blue' }]) +}) diff --git a/tests/responsive-and-variants-atrules.test.js b/tests/responsive-and-variants-atrules.test.js index 9d9ed5d85..4d4a0f507 100644 --- a/tests/responsive-and-variants-atrules.test.js +++ b/tests/responsive-and-variants-atrules.test.js @@ -1,157 +1,155 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('responsive and variants atrules', () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } +test('responsive and variants atrules', () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind components; - @tailwind utilities; - - @layer utilities { - @responsive { - .responsive-in-utilities { - color: blue; - } - } - @variants { - .variants-in-utilities { - color: red; - } - } - @responsive { - @variants { - .both-in-utilities { - color: green; - } - } - } - } + let input = css` + @tailwind components; + @tailwind utilities; + @layer utilities { @responsive { - .responsive-at-root { - color: white; + .responsive-in-utilities { + color: blue; } } @variants { - .variants-at-root { - color: orange; + .variants-in-utilities { + color: red; } } @responsive { @variants { - .both-at-root { - color: pink; + .both-in-utilities { + color: green; } } } + } - @layer components { - @responsive { - .responsive-in-components { - color: blue; - } - } - @variants { - .variants-in-components { - color: red; - } - } - @responsive { - @variants { - .both-in-components { - color: green; - } - } - } + @responsive { + .responsive-at-root { + color: white; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .responsive-in-components { - color: #00f; - } - .variants-in-components { - color: red; - } - .both-in-components { - color: green; - } - .responsive-in-utilities { - color: #00f; - } - .variants-in-utilities { - color: red; - } - .both-in-utilities { - color: green; - } - .responsive-at-root { - color: #fff; - } - .variants-at-root { - color: orange; - } + } + @variants { + .variants-at-root { + color: orange; + } + } + @responsive { + @variants { .both-at-root { color: pink; } - @media (min-width: 768px) { - .md\:focus\:responsive-in-components:focus { - color: #00f; - } - .md\:focus\:variants-in-components:focus { - color: red; - } - .md\:focus\:both-in-components:focus { + } + } + + @layer components { + @responsive { + .responsive-in-components { + color: blue; + } + } + @variants { + .variants-in-components { + color: red; + } + } + @responsive { + @variants { + .both-in-components { color: green; } - .md\:focus\:responsive-in-utilities:focus { - color: #00f; - } - .md\:focus\:variants-in-utilities:focus { - color: red; - } - .md\:focus\:both-in-utilities:focus { - color: green; - } - .md\:focus\:responsive-at-root:focus { - color: #fff; - } - .md\:focus\:variants-at-root:focus { - color: orange; - } - .md\:focus\:both-at-root:focus { - color: pink; - } } - `) - }) + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .responsive-in-components { + color: #00f; + } + .variants-in-components { + color: red; + } + .both-in-components { + color: green; + } + .responsive-in-utilities { + color: #00f; + } + .variants-in-utilities { + color: red; + } + .both-in-utilities { + color: green; + } + .responsive-at-root { + color: #fff; + } + .variants-at-root { + color: orange; + } + .both-at-root { + color: pink; + } + @media (min-width: 768px) { + .md\:focus\:responsive-in-components:focus { + color: #00f; + } + .md\:focus\:variants-in-components:focus { + color: red; + } + .md\:focus\:both-in-components:focus { + color: green; + } + .md\:focus\:responsive-in-utilities:focus { + color: #00f; + } + .md\:focus\:variants-in-utilities:focus { + color: red; + } + .md\:focus\:both-in-utilities:focus { + color: green; + } + .md\:focus\:responsive-at-root:focus { + color: #fff; + } + .md\:focus\:variants-at-root:focus { + color: orange; + } + .md\:focus\:both-at-root:focus { + color: pink; + } + } + `) }) }) diff --git a/tests/safelist.test.js b/tests/safelist.test.js index cbbd1e245..e2621f846 100644 --- a/tests/safelist.test.js +++ b/tests/safelist.test.js @@ -1,636 +1,491 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ stable, oxide }) => { - it('should not safelist anything', () => { - let config = { - content: [{ raw: html`
` }], - } +it('should not safelist anything', () => { + let config = { + content: [{ raw: html`
` }], + } - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist strings', () => { - let config = { - content: [{ raw: html`
` }], - safelist: ['mt-[20px]', 'font-bold', 'text-gray-200', 'hover:underline'], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .mt-\[20px\] { - margin-top: 20px; - } - .font-bold { - font-weight: 700; - } - .uppercase { - text-transform: uppercase; - } - .text-gray-200 { - --tw-text-opacity: 1; - color: rgb(229 231 235 / var(--tw-text-opacity)); - } - .hover\:underline:hover { - text-decoration-line: underline; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .mt-\[20px\] { - margin-top: 20px; - } - .font-bold { - font-weight: 700; - } - .uppercase { - text-transform: uppercase; - } - .text-gray-200 { - color: #e5e7eb; - } - .hover\:underline:hover { - text-decoration-line: underline; - } - `) - }) - }) - - it('should safelist based on a pattern regex', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .hover\:bg-red-200:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - background-color: #fee2e2; - } - .bg-red-200 { - background-color: #fecaca; - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - background-color: #fee2e2; - } - .hover\:bg-red-200:hover { - background-color: #fecaca; - } - `) - }) - }) - - it('should not generate duplicates', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - 'uppercase', - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .hover\:bg-red-200:hover { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - background-color: #fee2e2; - } - .bg-red-200 { - background-color: #fecaca; - } - .uppercase { - text-transform: uppercase; - } - .hover\:bg-red-100:hover { - background-color: #fee2e2; - } - .hover\:bg-red-200:hover { - background-color: #fecaca; - } - `) - }) - }) - - it('should safelist when using a custom prefix', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^tw-bg-red-(100|200)$/g, - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .tw-bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .tw-bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .tw-uppercase { - text-transform: uppercase; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .tw-bg-red-100 { - background-color: #fee2e2; - } - .tw-bg-red-200 { - background-color: #fecaca; - } - .tw-uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should not safelist when an empty list is provided', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should not safelist when an sparse/holey list is provided', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [, , ,], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should not safelist any invalid variants if provided', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^bg-(red)-(100|200)$/, - variants: ['foo', 'bar'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - --tw-bg-opacity: 1; - background-color: rgb(254 226 226 / var(--tw-bg-opacity)); - } - .bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); - } - .uppercase { - text-transform: uppercase; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .bg-red-100 { - background-color: #fee2e2; - } - .bg-red-200 { - background-color: #fecaca; - } - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist negatives based on a pattern regex', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^-top-1$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .-top-1 { - top: -0.25rem; - } - .uppercase { - text-transform: uppercase; - } - .hover\:-top-1:hover { - top: -0.25rem; - } - `) - }) - }) - - it('should safelist negatives based on a pattern regex', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^bg-red-(400|500)(\/(40|50))?$/, - variants: ['hover'], - }, - { - pattern: /^(fill|ring|text)-red-200\/50$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .bg-red-400 { - --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); - } - .bg-red-400\/40 { - background-color: #f8717166; - } - .bg-red-400\/50 { - background-color: #f8717180; - } - .bg-red-500 { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .bg-red-500\/40 { - background-color: #ef444466; - } - .bg-red-500\/50 { - background-color: #ef444480; - } - .fill-red-200\/50 { - fill: #fecaca80; - } - .uppercase { - text-transform: uppercase; - } - .text-red-200\/50 { - color: #fecaca80; - } - .ring-red-200\/50 { - --tw-ring-color: #fecaca80; - } - .hover\:bg-red-400:hover { - --tw-bg-opacity: 1; - background-color: rgb(248 113 113 / var(--tw-bg-opacity)); - } - .hover\:bg-red-400\/40:hover { - background-color: #f8717166; - } - .hover\:bg-red-400\/50:hover { - background-color: #f8717180; - } - .hover\:bg-red-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); - } - .hover\:bg-red-500\/40:hover { - background-color: #ef444466; - } - .hover\:bg-red-500\/50:hover { - background-color: #ef444480; - } - .hover\:fill-red-200\/50:hover { - fill: #fecaca80; - } - .hover\:text-red-200\/50:hover { - color: #fecaca80; - } - .hover\:ring-red-200\/50:hover { - --tw-ring-color: #fecaca80; - } - `) - }) - }) - - it('should safelist pattern regex with !important selector', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [{ pattern: /^!grid-cols-(4|5|6)$/ }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .\!grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)) !important; - } - .\!grid-cols-5 { - grid-template-columns: repeat(5, minmax(0, 1fr)) !important; - } - .\!grid-cols-6 { - grid-template-columns: repeat(6, minmax(0, 1fr)) !important; - } - .uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist pattern regex with custom prefix along with !important selector', () => { - let config = { - prefix: 'tw-', - content: [{ raw: html`
` }], - safelist: [{ pattern: /^!tw-grid-cols-(4|5|6)$/ }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .\!tw-grid-cols-4 { - grid-template-columns: repeat(4, minmax(0, 1fr)) !important; - } - .\!tw-grid-cols-5 { - grid-template-columns: repeat(5, minmax(0, 1fr)) !important; - } - .\!tw-grid-cols-6 { - grid-template-columns: repeat(6, minmax(0, 1fr)) !important; - } - .tw-uppercase { - text-transform: uppercase; - } - `) - }) - }) - - it('should safelist pattern regex having !important selector with variants', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^!bg-gray-(500|600|700|800)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-500 { - --tw-bg-opacity: 1 !important; - background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-600 { - --tw-bg-opacity: 1 !important; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-700 { - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-800 { - --tw-bg-opacity: 1 !important; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; - } - .uppercase { - text-transform: uppercase; - } - .hover\:\!bg-gray-500:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-600:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-700:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-800:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-500 { - background-color: #6b7280 !important; - } - .\!bg-gray-600 { - background-color: #4b5563 !important; - } - .\!bg-gray-700 { - background-color: #374151 !important; - } - .\!bg-gray-800 { - background-color: #1f2937 !important; - } - .uppercase { - text-transform: uppercase; - } - .hover\:\!bg-gray-500:hover { - background-color: #6b7280 !important; - } - .hover\:\!bg-gray-600:hover { - background-color: #4b5563 !important; - } - .hover\:\!bg-gray-700:hover { - background-color: #374151 !important; - } - .hover\:\!bg-gray-800:hover { - background-color: #1f2937 !important; - } - `) - }) - }) - - it('should safelist multiple patterns with !important selector', () => { - let config = { - content: [{ raw: html`
` }], - safelist: [ - { - pattern: /^!text-gray-(700|800|900)$/, - variants: ['hover'], - }, - { - pattern: /^!bg-gray-(200|300|400)$/, - variants: ['hover'], - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-200 { - --tw-bg-opacity: 1 !important; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-300 { - --tw-bg-opacity: 1 !important; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; - } - .\!bg-gray-400 { - --tw-bg-opacity: 1 !important; - background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; - } - .uppercase { - text-transform: uppercase; - } - .\!text-gray-700 { - --tw-text-opacity: 1 !important; - color: rgb(55 65 81 / var(--tw-text-opacity)) !important; - } - .\!text-gray-800 { - --tw-text-opacity: 1 !important; - color: rgb(31 41 55 / var(--tw-text-opacity)) !important; - } - .\!text-gray-900 { - --tw-text-opacity: 1 !important; - color: rgb(17 24 39 / var(--tw-text-opacity)) !important; - } - .hover\:\!bg-gray-200:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-300:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; - } - .hover\:\!bg-gray-400:hover { - --tw-bg-opacity: 1 !important; - background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; - } - .hover\:\!text-gray-700:hover { - --tw-text-opacity: 1 !important; - color: rgb(55 65 81 / var(--tw-text-opacity)) !important; - } - .hover\:\!text-gray-800:hover { - --tw-text-opacity: 1 !important; - color: rgb(31 41 55 / var(--tw-text-opacity)) !important; - } - .hover\:\!text-gray-900:hover { - --tw-text-opacity: 1 !important; - color: rgb(17 24 39 / var(--tw-text-opacity)) !important; - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .\!bg-gray-200 { - background-color: #e5e7eb !important; - } - .\!bg-gray-300 { - background-color: #d1d5db !important; - } - .\!bg-gray-400 { - background-color: #9ca3af !important; - } - .uppercase { - text-transform: uppercase; - } - .\!text-gray-700 { - color: #374151 !important; - } - .\!text-gray-800 { - color: #1f2937 !important; - } - .\!text-gray-900 { - color: #111827 !important; - } - .hover\:\!bg-gray-200:hover { - background-color: #e5e7eb !important; - } - .hover\:\!bg-gray-300:hover { - background-color: #d1d5db !important; - } - .hover\:\!bg-gray-400:hover { - background-color: #9ca3af !important; - } - .hover\:\!text-gray-700:hover { - color: #374151 !important; - } - .hover\:\!text-gray-800:hover { - color: #1f2937 !important; - } - .hover\:\!text-gray-900:hover { - color: #111827 !important; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist strings', () => { + let config = { + content: [{ raw: html`
` }], + safelist: ['mt-[20px]', 'font-bold', 'text-gray-200', 'hover:underline'], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .mt-\[20px\] { + margin-top: 20px; + } + .font-bold { + font-weight: 700; + } + .uppercase { + text-transform: uppercase; + } + .text-gray-200 { + --tw-text-opacity: 1; + color: rgb(229 231 235 / var(--tw-text-opacity)); + } + .hover\:underline:hover { + text-decoration-line: underline; + } + `) + }) +}) + +it('should safelist based on a pattern regex', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .uppercase { + text-transform: uppercase; + } + .hover\:bg-red-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .hover\:bg-red-200:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + `) + }) +}) + +it('should not generate duplicates', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + 'uppercase', + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .uppercase { + text-transform: uppercase; + } + .hover\:bg-red-100:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .hover\:bg-red-200:hover { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + `) + }) +}) + +it('should safelist when using a custom prefix', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^tw-bg-red-(100|200)$/g, + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .tw-bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .tw-bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .tw-uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should not safelist when an empty list is provided', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should not safelist when an sparse/holey list is provided', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [, , ,], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should not safelist any invalid variants if provided', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^bg-(red)-(100|200)$/, + variants: ['foo', 'bar'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-100 { + --tw-bg-opacity: 1; + background-color: rgb(254 226 226 / var(--tw-bg-opacity)); + } + .bg-red-200 { + --tw-bg-opacity: 1; + background-color: rgb(254 202 202 / var(--tw-bg-opacity)); + } + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist negatives based on a pattern regex', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^-top-1$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .-top-1 { + top: -0.25rem; + } + .uppercase { + text-transform: uppercase; + } + .hover\:-top-1:hover { + top: -0.25rem; + } + `) + }) +}) + +it('should safelist negatives based on a pattern regex', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^bg-red-(400|500)(\/(40|50))?$/, + variants: ['hover'], + }, + { + pattern: /^(fill|ring|text)-red-200\/50$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .bg-red-400 { + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + } + .bg-red-400\/40 { + background-color: #f8717166; + } + .bg-red-400\/50 { + background-color: #f8717180; + } + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + .bg-red-500\/40 { + background-color: #ef444466; + } + .bg-red-500\/50 { + background-color: #ef444480; + } + .fill-red-200\/50 { + fill: #fecaca80; + } + .uppercase { + text-transform: uppercase; + } + .text-red-200\/50 { + color: #fecaca80; + } + .ring-red-200\/50 { + --tw-ring-color: #fecaca80; + } + .hover\:bg-red-400:hover { + --tw-bg-opacity: 1; + background-color: rgb(248 113 113 / var(--tw-bg-opacity)); + } + .hover\:bg-red-400\/40:hover { + background-color: #f8717166; + } + .hover\:bg-red-400\/50:hover { + background-color: #f8717180; + } + .hover\:bg-red-500:hover { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + .hover\:bg-red-500\/40:hover { + background-color: #ef444466; + } + .hover\:bg-red-500\/50:hover { + background-color: #ef444480; + } + .hover\:fill-red-200\/50:hover { + fill: #fecaca80; + } + .hover\:text-red-200\/50:hover { + color: #fecaca80; + } + .hover\:ring-red-200\/50:hover { + --tw-ring-color: #fecaca80; + } + `) + }) +}) + +it('should safelist pattern regex with !important selector', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [{ pattern: /^!grid-cols-(4|5|6)$/ }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .\!grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + } + .\!grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)) !important; + } + .\!grid-cols-6 { + grid-template-columns: repeat(6, minmax(0, 1fr)) !important; + } + .uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist pattern regex with custom prefix along with !important selector', () => { + let config = { + prefix: 'tw-', + content: [{ raw: html`
` }], + safelist: [{ pattern: /^!tw-grid-cols-(4|5|6)$/ }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .\!tw-grid-cols-4 { + grid-template-columns: repeat(4, minmax(0, 1fr)) !important; + } + .\!tw-grid-cols-5 { + grid-template-columns: repeat(5, minmax(0, 1fr)) !important; + } + .\!tw-grid-cols-6 { + grid-template-columns: repeat(6, minmax(0, 1fr)) !important; + } + .tw-uppercase { + text-transform: uppercase; + } + `) + }) +}) + +it('should safelist pattern regex having !important selector with variants', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^!bg-gray-(500|600|700|800)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\!bg-gray-500 { + --tw-bg-opacity: 1 !important; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-600 { + --tw-bg-opacity: 1 !important; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-700 { + --tw-bg-opacity: 1 !important; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-800 { + --tw-bg-opacity: 1 !important; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; + } + .uppercase { + text-transform: uppercase; + } + .hover\:\!bg-gray-500:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(107 114 128 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-600:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(75 85 99 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-700:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(55 65 81 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-800:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(31 41 55 / var(--tw-bg-opacity)) !important; + } + `) + }) +}) + +it('should safelist multiple patterns with !important selector', () => { + let config = { + content: [{ raw: html`
` }], + safelist: [ + { + pattern: /^!text-gray-(700|800|900)$/, + variants: ['hover'], + }, + { + pattern: /^!bg-gray-(200|300|400)$/, + variants: ['hover'], + }, + ], + } + + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .\!bg-gray-200 { + --tw-bg-opacity: 1 !important; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-300 { + --tw-bg-opacity: 1 !important; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; + } + .\!bg-gray-400 { + --tw-bg-opacity: 1 !important; + background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; + } + .uppercase { + text-transform: uppercase; + } + .\!text-gray-700 { + --tw-text-opacity: 1 !important; + color: rgb(55 65 81 / var(--tw-text-opacity)) !important; + } + .\!text-gray-800 { + --tw-text-opacity: 1 !important; + color: rgb(31 41 55 / var(--tw-text-opacity)) !important; + } + .\!text-gray-900 { + --tw-text-opacity: 1 !important; + color: rgb(17 24 39 / var(--tw-text-opacity)) !important; + } + .hover\:\!bg-gray-200:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(229 231 235 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-300:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(209 213 219 / var(--tw-bg-opacity)) !important; + } + .hover\:\!bg-gray-400:hover { + --tw-bg-opacity: 1 !important; + background-color: rgb(156 163 175 / var(--tw-bg-opacity)) !important; + } + .hover\:\!text-gray-700:hover { + --tw-text-opacity: 1 !important; + color: rgb(55 65 81 / var(--tw-text-opacity)) !important; + } + .hover\:\!text-gray-800:hover { + --tw-text-opacity: 1 !important; + color: rgb(31 41 55 / var(--tw-text-opacity)) !important; + } + .hover\:\!text-gray-900:hover { + --tw-text-opacity: 1 !important; + color: rgb(17 24 39 / var(--tw-text-opacity)) !important; + } + `) }) }) diff --git a/tests/screenAtRule.test.js b/tests/screenAtRule.test.js index 6352fcde0..b6f1723c3 100644 --- a/tests/screenAtRule.test.js +++ b/tests/screenAtRule.test.js @@ -1,60 +1,58 @@ import postcss from 'postcss' import plugin from '../src/lib/substituteScreenAtRules' import config from '../stubs/config.full.js' -import { crosscheck, css } from './util/run' +import { css } from './util/run' function run(input, opts = config) { return postcss([plugin({ tailwindConfig: opts })]).process(input, { from: undefined }) } -crosscheck(() => { - test('it can generate media queries from configured screen sizes', () => { - let input = css` - @screen sm { +test('it can generate media queries from configured screen sizes', () => { + let input = css` + @screen sm { + .banana { + color: yellow; + } + } + @screen md { + .banana { + color: red; + } + } + @screen lg { + .banana { + color: green; + } + } + ` + + return run(input, { + theme: { + screens: { + sm: '500px', + md: '750px', + lg: '1000px', + }, + }, + separator: ':', + }).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 500px) { .banana { - color: yellow; + color: #ff0; } } - @screen md { + @media (min-width: 750px) { .banana { color: red; } } - @screen lg { + @media (min-width: 1000px) { .banana { color: green; } } - ` - - return run(input, { - theme: { - screens: { - sm: '500px', - md: '750px', - lg: '1000px', - }, - }, - separator: ':', - }).then((result) => { - expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { - .banana { - color: #ff0; - } - } - @media (min-width: 750px) { - .banana { - color: red; - } - } - @media (min-width: 1000px) { - .banana { - color: green; - } - } - `) - expect(result.warnings().length).toBe(0) - }) + `) + expect(result.warnings().length).toBe(0) }) }) diff --git a/tests/shared-state.test.js b/tests/shared-state.test.js index 4791d07dc..a3a9f2870 100644 --- a/tests/shared-state.test.js +++ b/tests/shared-state.test.js @@ -1,23 +1,20 @@ import { resolveDebug } from '../src/lib/sharedState' -import { crosscheck } from './util/run' -crosscheck(() => { - it.each` - value | expected - ${'true'} | ${true} - ${'1'} | ${true} - ${'false'} | ${false} - ${'0'} | ${false} - ${'*'} | ${true} - ${'tailwindcss'} | ${true} - ${'tailwindcss:*'} | ${true} - ${'other,tailwindcss'} | ${true} - ${'other,tailwindcss:*'} | ${true} - ${'other,-tailwindcss'} | ${false} - ${'other,-tailwindcss:*'} | ${false} - ${'-tailwindcss'} | ${false} - ${'-tailwindcss:*'} | ${false} - `('should resolve the debug ($value) flag correctly ($expected)', ({ value, expected }) => { - expect(resolveDebug(value)).toBe(expected) - }) +it.each` + value | expected + ${'true'} | ${true} + ${'1'} | ${true} + ${'false'} | ${false} + ${'0'} | ${false} + ${'*'} | ${true} + ${'tailwindcss'} | ${true} + ${'tailwindcss:*'} | ${true} + ${'other,tailwindcss'} | ${true} + ${'other,tailwindcss:*'} | ${true} + ${'other,-tailwindcss'} | ${false} + ${'other,-tailwindcss:*'} | ${false} + ${'-tailwindcss'} | ${false} + ${'-tailwindcss:*'} | ${false} +`('should resolve the debug ($value) flag correctly ($expected)', ({ value, expected }) => { + expect(resolveDebug(value)).toBe(expected) }) diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index e0839bf6e..5f3a99902 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -1,537 +1,522 @@ import postcss from 'postcss' import { parseSourceMaps } from './util/source-maps' -import { crosscheck, runWithSourceMaps as run, html, css, map } from './util/run' +import { runWithSourceMaps as run, html, css, map } from './util/run' -crosscheck(({ stable, oxide }) => { - oxide.test.todo('apply generates source maps') - stable.test('apply generates source maps', async () => { - let config = { - content: [ - { - raw: html` -
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - .with-declaration { - background-color: red; - @apply h-4 w-4 bg-green-500; - } - - .with-comment { - /* sourcemap will work here too */ - @apply h-4 w-4 bg-red-500; - } - - .just-apply { - @apply h-4 w-4 bg-black; - } - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toEqual([ - '2:6 -> 2:6', - '3:8-29 -> 3:8-29', - '4:8-35 -> 4:8-20', - '4:8-35 -> 5:8-19', - '4:8-35 -> 6:8-26', - '4:8-35 -> 7:8-63', - '5:6 -> 8:6', - '7:6 -> 10:6', - '8:8-41 -> 11:8-41', - '9:8-33 -> 12:8-20', - '9:8-33 -> 13:8-19', - '9:8-33 -> 14:8-26', - '9:8-33 -> 15:8-63', - '10:6 -> 16:6', - '13:8 -> 18:6', - '13:8-31 -> 19:8-20', - '13:8-31 -> 20:8-19', - '13:8-31 -> 21:8-26', - '13:8 -> 22:8', - '13:31 -> 23:0', - ]) - }) - - oxide.test.todo('preflight + base have source maps') - stable.test('preflight + base have source maps', async () => { - let config = { - content: [], - } - - let input = css` - @tailwind base; - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toEqual([ - '2:6 -> 1:0', - '2:20-6 -> 3:1-2', - '2:20 -> 6:1', - '2:6 -> 8:0', - '2:6-20 -> 11:2-32', - '2:6-20 -> 12:2-25', - '2:6-20 -> 13:2-29', - '2:6-20 -> 14:2-31', - '2:20 -> 15:0', - '2:6 -> 17:0', - '2:6-20 -> 19:2-18', - '2:20 -> 20:0', - '2:6 -> 22:0', - '2:20 -> 29:1', - '2:6 -> 31:0', - '2:6-20 -> 32:2-26', - '2:6-20 -> 33:2-40', - '2:6-20 -> 34:2-26', - '2:6-20 -> 35:2-21', - '2:6-20 -> 36:2-230', - '2:6-20 -> 37:2-39', - '2:6-20 -> 38:2-41', - '2:20 -> 39:0', - '2:6 -> 41:0', - '2:20 -> 44:1', - '2:6 -> 46:0', - '2:6-20 -> 47:2-19', - '2:6-20 -> 48:2-30', - '2:20 -> 49:0', - '2:6 -> 51:0', - '2:20 -> 55:1', - '2:6 -> 57:0', - '2:6-20 -> 58:2-19', - '2:6-20 -> 59:2-24', - '2:6-20 -> 60:2-31', - '2:20 -> 61:0', - '2:6 -> 63:0', - '2:20 -> 65:1', - '2:6 -> 67:0', - '2:6-20 -> 68:2-35', - '2:20 -> 69:0', - '2:6 -> 71:0', - '2:20 -> 73:1', - '2:6 -> 75:0', - '2:6-20 -> 81:2-20', - '2:6-20 -> 82:2-22', - '2:20 -> 83:0', - '2:6 -> 85:0', - '2:20 -> 87:1', - '2:6 -> 89:0', - '2:6-20 -> 90:2-16', - '2:6-20 -> 91:2-26', - '2:20 -> 92:0', - '2:6 -> 94:0', - '2:20 -> 96:1', - '2:6 -> 98:0', - '2:6-20 -> 100:2-21', - '2:20 -> 101:0', - '2:6 -> 103:0', - '2:20 -> 106:1', - '2:6 -> 108:0', - '2:6-20 -> 112:2-121', - '2:6-20 -> 113:2-24', - '2:20 -> 114:0', - '2:6 -> 116:0', - '2:20 -> 118:1', - '2:6 -> 120:0', - '2:6-20 -> 121:2-16', - '2:20 -> 122:0', - '2:6 -> 124:0', - '2:20 -> 126:1', - '2:6 -> 128:0', - '2:6-20 -> 130:2-16', - '2:6-20 -> 131:2-16', - '2:6-20 -> 132:2-20', - '2:6-20 -> 133:2-26', - '2:20 -> 134:0', - '2:6 -> 136:0', - '2:6-20 -> 137:2-17', - '2:20 -> 138:0', - '2:6 -> 140:0', - '2:6-20 -> 141:2-13', - '2:20 -> 142:0', - '2:6 -> 144:0', - '2:20 -> 148:1', - '2:6 -> 150:0', - '2:6-20 -> 151:2-24', - '2:6-20 -> 152:2-31', - '2:6-20 -> 153:2-35', - '2:20 -> 154:0', - '2:6 -> 156:0', - '2:20 -> 160:1', - '2:6 -> 162:0', - '2:6-20 -> 167:2-30', - '2:6-20 -> 168:2-40', - '2:6-20 -> 169:2-42', - '2:6-20 -> 170:2-25', - '2:6-20 -> 171:2-30', - '2:6-20 -> 172:2-30', - '2:6-20 -> 173:2-24', - '2:6-20 -> 174:2-19', - '2:6-20 -> 175:2-20', - '2:20 -> 176:0', - '2:6 -> 178:0', - '2:20 -> 180:1', - '2:6 -> 182:0', - '2:6-20 -> 184:2-22', - '2:20 -> 185:0', - '2:6 -> 187:0', - '2:20 -> 190:1', - '2:6 -> 192:0', - '2:6-20 -> 196:2-36', - '2:6-20 -> 197:2-39', - '2:6-20 -> 198:2-32', - '2:20 -> 199:0', - '2:6 -> 201:0', - '2:20 -> 203:1', - '2:6 -> 205:0', - '2:6-20 -> 206:2-15', - '2:20 -> 207:0', - '2:6 -> 209:0', - '2:20 -> 211:1', - '2:6 -> 213:0', - '2:6-20 -> 214:2-18', - '2:20 -> 215:0', - '2:6 -> 217:0', - '2:20 -> 219:1', - '2:6 -> 221:0', - '2:6-20 -> 222:2-26', - '2:20 -> 223:0', - '2:6 -> 225:0', - '2:20 -> 227:1', - '2:6 -> 229:0', - '2:6-20 -> 231:2-14', - '2:20 -> 232:0', - '2:6 -> 234:0', - '2:20 -> 237:1', - '2:6 -> 239:0', - '2:6-20 -> 240:2-39', - '2:6-20 -> 241:2-30', - '2:20 -> 242:0', - '2:6 -> 244:0', - '2:20 -> 246:1', - '2:6 -> 248:0', - '2:6-20 -> 249:2-26', - '2:20 -> 250:0', - '2:6 -> 252:0', - '2:20 -> 255:1', - '2:6 -> 257:0', - '2:6-20 -> 258:2-36', - '2:6-20 -> 259:2-23', - '2:20 -> 260:0', - '2:6 -> 262:0', - '2:20 -> 264:1', - '2:6 -> 266:0', - '2:6-20 -> 267:2-20', - '2:20 -> 268:0', - '2:6 -> 270:0', - '2:20 -> 272:1', - '2:6 -> 274:0', - '2:6-20 -> 287:2-11', - '2:20 -> 288:0', - '2:6 -> 290:0', - '2:6-20 -> 291:2-11', - '2:6-20 -> 292:2-12', - '2:20 -> 293:0', - '2:6 -> 295:0', - '2:6-20 -> 296:2-12', - '2:20 -> 297:0', - '2:6 -> 299:0', - '2:6-20 -> 302:2-18', - '2:6-20 -> 303:2-11', - '2:6-20 -> 304:2-12', - '2:20 -> 305:0', - '2:6 -> 307:0', - '2:6-20 -> 308:2-12', - '2:20 -> 309:0', - '2:6 -> 311:0', - '2:20 -> 313:1', - '2:6 -> 315:0', - '2:6-20 -> 316:2-18', - '2:20 -> 317:0', - '2:6 -> 319:0', - '2:20 -> 322:1', - '2:6 -> 324:0', - '2:6-20 -> 326:2-20', - '2:6-20 -> 327:2-24', - '2:20 -> 328:0', - '2:6 -> 330:0', - '2:20 -> 332:1', - '2:6 -> 334:0', - '2:6-20 -> 336:2-17', - '2:20 -> 337:0', - '2:6 -> 339:0', - '2:20 -> 341:1', - '2:6 -> 342:0', - '2:6-20 -> 343:2-17', - '2:20 -> 344:0', - '2:6 -> 346:0', - '2:20 -> 350:1', - '2:6 -> 352:0', - '2:6-20 -> 360:2-24', - '2:6-20 -> 361:2-32', - '2:20 -> 362:0', - '2:6 -> 364:0', - '2:20 -> 366:1', - '2:6 -> 368:0', - '2:6-20 -> 370:2-17', - '2:6-20 -> 371:2-14', - '2:20 -> 372:0', - '2:6-20 -> 374:0-72', - '2:6 -> 375:0', - '2:6-20 -> 376:2-15', - '2:20 -> 377:0', - '2:6 -> 379:0', - '2:6-20 -> 380:2-26', - '2:6-20 -> 381:2-26', - '2:6-20 -> 382:2-21', - '2:6-20 -> 383:2-21', - '2:6-20 -> 384:2-16', - '2:6-20 -> 385:2-16', - '2:6-20 -> 386:2-16', - '2:6-20 -> 387:2-17', - '2:6-20 -> 388:2-17', - '2:6-20 -> 389:2-15', - '2:6-20 -> 390:2-15', - '2:6-20 -> 391:2-20', - '2:6-20 -> 392:2-40', - '2:6-20 -> 393:2-32', - '2:6-20 -> 394:2-31', - '2:6-20 -> 395:2-30', - '2:6-20 -> 396:2-17', - '2:6-20 -> 397:2-22', - '2:6-20 -> 398:2-24', - '2:6-20 -> 399:2-25', - '2:6-20 -> 400:2-26', - '2:6-20 -> 401:2-20', - '2:6-20 -> 402:2-29', - '2:6-20 -> 403:2-30', - '2:6-20 -> 404:2-40', - '2:6-20 -> 405:2-36', - '2:6-20 -> 406:2-29', - '2:6-20 -> 407:2-24', - '2:6-20 -> 408:2-32', - '2:6-20 -> 409:2-14', - '2:6-20 -> 410:2-20', - '2:6-20 -> 411:2-18', - '2:6-20 -> 412:2-19', - '2:6-20 -> 413:2-20', - '2:6-20 -> 414:2-16', - '2:6-20 -> 415:2-18', - '2:6-20 -> 416:2-15', - '2:6-20 -> 417:2-21', - '2:6-20 -> 418:2-23', - '2:6-20 -> 419:2-29', - '2:6-20 -> 420:2-27', - '2:6-20 -> 421:2-28', - '2:6-20 -> 422:2-29', - '2:6-20 -> 423:2-25', - '2:6-20 -> 424:2-26', - '2:6-20 -> 425:2-27', - '2:6 -> 426:2', - '2:20 -> 427:0', - '2:6 -> 429:0', - '2:6-20 -> 430:2-26', - '2:6-20 -> 431:2-26', - '2:6-20 -> 432:2-21', - '2:6-20 -> 433:2-21', - '2:6-20 -> 434:2-16', - '2:6-20 -> 435:2-16', - '2:6-20 -> 436:2-16', - '2:6-20 -> 437:2-17', - '2:6-20 -> 438:2-17', - '2:6-20 -> 439:2-15', - '2:6-20 -> 440:2-15', - '2:6-20 -> 441:2-20', - '2:6-20 -> 442:2-40', - '2:6-20 -> 443:2-32', - '2:6-20 -> 444:2-31', - '2:6-20 -> 445:2-30', - '2:6-20 -> 446:2-17', - '2:6-20 -> 447:2-22', - '2:6-20 -> 448:2-24', - '2:6-20 -> 449:2-25', - '2:6-20 -> 450:2-26', - '2:6-20 -> 451:2-20', - '2:6-20 -> 452:2-29', - '2:6-20 -> 453:2-30', - '2:6-20 -> 454:2-40', - '2:6-20 -> 455:2-36', - '2:6-20 -> 456:2-29', - '2:6-20 -> 457:2-24', - '2:6-20 -> 458:2-32', - '2:6-20 -> 459:2-14', - '2:6-20 -> 460:2-20', - '2:6-20 -> 461:2-18', - '2:6-20 -> 462:2-19', - '2:6-20 -> 463:2-20', - '2:6-20 -> 464:2-16', - '2:6-20 -> 465:2-18', - '2:6-20 -> 466:2-15', - '2:6-20 -> 467:2-21', - '2:6-20 -> 468:2-23', - '2:6-20 -> 469:2-29', - '2:6-20 -> 470:2-27', - '2:6-20 -> 471:2-28', - '2:6-20 -> 472:2-29', - '2:6-20 -> 473:2-25', - '2:6-20 -> 474:2-26', - '2:6-20 -> 475:2-27', - '2:6 -> 476:2', - '2:20 -> 477:0', - ]) - }) - - oxide.test.todo('utilities have source maps') - stable.test('utilities have source maps', async () => { - let config = { - content: [{ raw: `text-red-500` }], - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toStrictEqual([ - '2:6 -> 1:0', - '2:6-25 -> 2:4-24', - '2:6 -> 3:4', - '2:25 -> 4:0', - ]) - }) - - oxide.test.todo('components have source maps') - stable.test('components have source maps', async () => { - let config = { - content: [{ raw: `container` }], - } - - let input = css` - @tailwind components; - ` - - let result = await run(input, config) - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - expect(sources.length).toBe(1) - - expect(annotations).toEqual([ - '2:6 -> 1:0', - '2:6 -> 2:4', - '2:26 -> 3:0', - '2:6 -> 4:0', - '2:6 -> 5:4', - '2:6 -> 6:8', - '2:26 -> 7:4', - '2:26 -> 8:0', - '2:6 -> 9:0', - '2:6 -> 10:4', - '2:6 -> 11:8', - '2:26 -> 12:4', - '2:26 -> 13:0', - '2:6 -> 14:0', - '2:6 -> 15:4', - '2:6 -> 16:8', - '2:26 -> 17:4', - '2:26 -> 18:0', - '2:6 -> 19:0', - '2:6 -> 20:4', - '2:6 -> 21:8', - '2:26 -> 22:4', - '2:26 -> 23:0', - '2:6 -> 24:0', - '2:6 -> 25:4', - '2:6 -> 26:8', - '2:26 -> 27:4', - '2:26 -> 28:0', - ]) - }) - - oxide.test.todo('source maps for layer rules are not rewritten to point to @tailwind directives') - stable.test( - 'source maps for layer rules are not rewritten to point to @tailwind directives', - async () => { - let config = { - content: [{ raw: `font-normal foo hover:foo` }], - } - - let utilitiesFile = postcss.parse( - css` - @tailwind utilities; +test.skip('apply generates source maps', async () => { + let config = { + content: [ + { + raw: html` +
+
+
`, - { from: 'components.css', map: { prev: map } } - ) + }, + ], + corePlugins: { preflight: false }, + } - let mainCssFile = postcss.parse( - css` - @layer utilities { - .foo { - background-color: red; - } - } - `, - { from: 'input.css', map: { prev: map } } - ) - - // Just pretend that there's an @import in `mainCssFile` that imports the nodes from `utilitiesFile` - let input = postcss.root({ - nodes: [...utilitiesFile.nodes, ...mainCssFile.nodes], - source: mainCssFile.source, - }) - - let result = await run(input, config) - - let { sources, annotations } = parseSourceMaps(result) - - // All CSS generated by Tailwind CSS should be annotated with source maps - // And always be able to point to the original source file - expect(sources).not.toContain('') - - // And we should see that the source map for the layer rule is not rewritten - // to point to the @tailwind directive but instead points to the original - expect(sources.length).toBe(2) - expect(sources).toEqual(['components.css', 'input.css']) - - expect(annotations).toEqual([ - '2:10 -> 1:0', - '2:10 -> 2:14', - '2:29 -> 3:0', - '3:12 -> 4:12', - '4:14-35 -> 5:14-35', - '5:12 -> 6:12', - '3:12 -> 7:12', - '4:14-35 -> 8:14-35', - '5:12 -> 9:12', - ]) + let input = css` + .with-declaration { + background-color: red; + @apply h-4 w-4 bg-green-500; } - ) + + .with-comment { + /* sourcemap will work here too */ + @apply h-4 w-4 bg-red-500; + } + + .just-apply { + @apply h-4 w-4 bg-black; + } + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(1) + + expect(annotations).toEqual([ + '2:6 -> 2:6', + '3:8-29 -> 3:8-29', + '4:8-35 -> 4:8-20', + '4:8-35 -> 5:8-19', + '4:8-35 -> 6:8-26', + '4:8-35 -> 7:8-63', + '5:6 -> 8:6', + '7:6 -> 10:6', + '8:8-41 -> 11:8-41', + '9:8-33 -> 12:8-20', + '9:8-33 -> 13:8-19', + '9:8-33 -> 14:8-26', + '9:8-33 -> 15:8-63', + '10:6 -> 16:6', + '13:8 -> 18:6', + '13:8-31 -> 19:8-20', + '13:8-31 -> 20:8-19', + '13:8-31 -> 21:8-26', + '13:8 -> 22:8', + '13:31 -> 23:0', + ]) +}) + +test.skip('preflight + base have source maps', async () => { + let config = { + content: [], + } + + let input = css` + @tailwind base; + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(1) + + expect(annotations).toEqual([ + '2:6 -> 1:0', + '2:20-6 -> 3:1-2', + '2:20 -> 6:1', + '2:6 -> 8:0', + '2:6-20 -> 11:2-32', + '2:6-20 -> 12:2-25', + '2:6-20 -> 13:2-29', + '2:6-20 -> 14:2-31', + '2:20 -> 15:0', + '2:6 -> 17:0', + '2:6-20 -> 19:2-18', + '2:20 -> 20:0', + '2:6 -> 22:0', + '2:20 -> 29:1', + '2:6 -> 31:0', + '2:6-20 -> 32:2-26', + '2:6-20 -> 33:2-40', + '2:6-20 -> 34:2-26', + '2:6-20 -> 35:2-21', + '2:6-20 -> 36:2-230', + '2:6-20 -> 37:2-39', + '2:6-20 -> 38:2-41', + '2:20 -> 39:0', + '2:6 -> 41:0', + '2:20 -> 44:1', + '2:6 -> 46:0', + '2:6-20 -> 47:2-19', + '2:6-20 -> 48:2-30', + '2:20 -> 49:0', + '2:6 -> 51:0', + '2:20 -> 55:1', + '2:6 -> 57:0', + '2:6-20 -> 58:2-19', + '2:6-20 -> 59:2-24', + '2:6-20 -> 60:2-31', + '2:20 -> 61:0', + '2:6 -> 63:0', + '2:20 -> 65:1', + '2:6 -> 67:0', + '2:6-20 -> 68:2-35', + '2:20 -> 69:0', + '2:6 -> 71:0', + '2:20 -> 73:1', + '2:6 -> 75:0', + '2:6-20 -> 81:2-20', + '2:6-20 -> 82:2-22', + '2:20 -> 83:0', + '2:6 -> 85:0', + '2:20 -> 87:1', + '2:6 -> 89:0', + '2:6-20 -> 90:2-16', + '2:6-20 -> 91:2-26', + '2:20 -> 92:0', + '2:6 -> 94:0', + '2:20 -> 96:1', + '2:6 -> 98:0', + '2:6-20 -> 100:2-21', + '2:20 -> 101:0', + '2:6 -> 103:0', + '2:20 -> 106:1', + '2:6 -> 108:0', + '2:6-20 -> 112:2-121', + '2:6-20 -> 113:2-24', + '2:20 -> 114:0', + '2:6 -> 116:0', + '2:20 -> 118:1', + '2:6 -> 120:0', + '2:6-20 -> 121:2-16', + '2:20 -> 122:0', + '2:6 -> 124:0', + '2:20 -> 126:1', + '2:6 -> 128:0', + '2:6-20 -> 130:2-16', + '2:6-20 -> 131:2-16', + '2:6-20 -> 132:2-20', + '2:6-20 -> 133:2-26', + '2:20 -> 134:0', + '2:6 -> 136:0', + '2:6-20 -> 137:2-17', + '2:20 -> 138:0', + '2:6 -> 140:0', + '2:6-20 -> 141:2-13', + '2:20 -> 142:0', + '2:6 -> 144:0', + '2:20 -> 148:1', + '2:6 -> 150:0', + '2:6-20 -> 151:2-24', + '2:6-20 -> 152:2-31', + '2:6-20 -> 153:2-35', + '2:20 -> 154:0', + '2:6 -> 156:0', + '2:20 -> 160:1', + '2:6 -> 162:0', + '2:6-20 -> 167:2-30', + '2:6-20 -> 168:2-40', + '2:6-20 -> 169:2-42', + '2:6-20 -> 170:2-25', + '2:6-20 -> 171:2-30', + '2:6-20 -> 172:2-30', + '2:6-20 -> 173:2-24', + '2:6-20 -> 174:2-19', + '2:6-20 -> 175:2-20', + '2:20 -> 176:0', + '2:6 -> 178:0', + '2:20 -> 180:1', + '2:6 -> 182:0', + '2:6-20 -> 184:2-22', + '2:20 -> 185:0', + '2:6 -> 187:0', + '2:20 -> 190:1', + '2:6 -> 192:0', + '2:6-20 -> 196:2-36', + '2:6-20 -> 197:2-39', + '2:6-20 -> 198:2-32', + '2:20 -> 199:0', + '2:6 -> 201:0', + '2:20 -> 203:1', + '2:6 -> 205:0', + '2:6-20 -> 206:2-15', + '2:20 -> 207:0', + '2:6 -> 209:0', + '2:20 -> 211:1', + '2:6 -> 213:0', + '2:6-20 -> 214:2-18', + '2:20 -> 215:0', + '2:6 -> 217:0', + '2:20 -> 219:1', + '2:6 -> 221:0', + '2:6-20 -> 222:2-26', + '2:20 -> 223:0', + '2:6 -> 225:0', + '2:20 -> 227:1', + '2:6 -> 229:0', + '2:6-20 -> 231:2-14', + '2:20 -> 232:0', + '2:6 -> 234:0', + '2:20 -> 237:1', + '2:6 -> 239:0', + '2:6-20 -> 240:2-39', + '2:6-20 -> 241:2-30', + '2:20 -> 242:0', + '2:6 -> 244:0', + '2:20 -> 246:1', + '2:6 -> 248:0', + '2:6-20 -> 249:2-26', + '2:20 -> 250:0', + '2:6 -> 252:0', + '2:20 -> 255:1', + '2:6 -> 257:0', + '2:6-20 -> 258:2-36', + '2:6-20 -> 259:2-23', + '2:20 -> 260:0', + '2:6 -> 262:0', + '2:20 -> 264:1', + '2:6 -> 266:0', + '2:6-20 -> 267:2-20', + '2:20 -> 268:0', + '2:6 -> 270:0', + '2:20 -> 272:1', + '2:6 -> 274:0', + '2:6-20 -> 287:2-11', + '2:20 -> 288:0', + '2:6 -> 290:0', + '2:6-20 -> 291:2-11', + '2:6-20 -> 292:2-12', + '2:20 -> 293:0', + '2:6 -> 295:0', + '2:6-20 -> 296:2-12', + '2:20 -> 297:0', + '2:6 -> 299:0', + '2:6-20 -> 302:2-18', + '2:6-20 -> 303:2-11', + '2:6-20 -> 304:2-12', + '2:20 -> 305:0', + '2:6 -> 307:0', + '2:6-20 -> 308:2-12', + '2:20 -> 309:0', + '2:6 -> 311:0', + '2:20 -> 313:1', + '2:6 -> 315:0', + '2:6-20 -> 316:2-18', + '2:20 -> 317:0', + '2:6 -> 319:0', + '2:20 -> 322:1', + '2:6 -> 324:0', + '2:6-20 -> 326:2-20', + '2:6-20 -> 327:2-24', + '2:20 -> 328:0', + '2:6 -> 330:0', + '2:20 -> 332:1', + '2:6 -> 334:0', + '2:6-20 -> 336:2-17', + '2:20 -> 337:0', + '2:6 -> 339:0', + '2:20 -> 341:1', + '2:6 -> 342:0', + '2:6-20 -> 343:2-17', + '2:20 -> 344:0', + '2:6 -> 346:0', + '2:20 -> 350:1', + '2:6 -> 352:0', + '2:6-20 -> 360:2-24', + '2:6-20 -> 361:2-32', + '2:20 -> 362:0', + '2:6 -> 364:0', + '2:20 -> 366:1', + '2:6 -> 368:0', + '2:6-20 -> 370:2-17', + '2:6-20 -> 371:2-14', + '2:20 -> 372:0', + '2:6-20 -> 374:0-72', + '2:6 -> 375:0', + '2:6-20 -> 376:2-15', + '2:20 -> 377:0', + '2:6 -> 379:0', + '2:6-20 -> 380:2-26', + '2:6-20 -> 381:2-26', + '2:6-20 -> 382:2-21', + '2:6-20 -> 383:2-21', + '2:6-20 -> 384:2-16', + '2:6-20 -> 385:2-16', + '2:6-20 -> 386:2-16', + '2:6-20 -> 387:2-17', + '2:6-20 -> 388:2-17', + '2:6-20 -> 389:2-15', + '2:6-20 -> 390:2-15', + '2:6-20 -> 391:2-20', + '2:6-20 -> 392:2-40', + '2:6-20 -> 393:2-32', + '2:6-20 -> 394:2-31', + '2:6-20 -> 395:2-30', + '2:6-20 -> 396:2-17', + '2:6-20 -> 397:2-22', + '2:6-20 -> 398:2-24', + '2:6-20 -> 399:2-25', + '2:6-20 -> 400:2-26', + '2:6-20 -> 401:2-20', + '2:6-20 -> 402:2-29', + '2:6-20 -> 403:2-30', + '2:6-20 -> 404:2-40', + '2:6-20 -> 405:2-36', + '2:6-20 -> 406:2-29', + '2:6-20 -> 407:2-24', + '2:6-20 -> 408:2-32', + '2:6-20 -> 409:2-14', + '2:6-20 -> 410:2-20', + '2:6-20 -> 411:2-18', + '2:6-20 -> 412:2-19', + '2:6-20 -> 413:2-20', + '2:6-20 -> 414:2-16', + '2:6-20 -> 415:2-18', + '2:6-20 -> 416:2-15', + '2:6-20 -> 417:2-21', + '2:6-20 -> 418:2-23', + '2:6-20 -> 419:2-29', + '2:6-20 -> 420:2-27', + '2:6-20 -> 421:2-28', + '2:6-20 -> 422:2-29', + '2:6-20 -> 423:2-25', + '2:6-20 -> 424:2-26', + '2:6-20 -> 425:2-27', + '2:6 -> 426:2', + '2:20 -> 427:0', + '2:6 -> 429:0', + '2:6-20 -> 430:2-26', + '2:6-20 -> 431:2-26', + '2:6-20 -> 432:2-21', + '2:6-20 -> 433:2-21', + '2:6-20 -> 434:2-16', + '2:6-20 -> 435:2-16', + '2:6-20 -> 436:2-16', + '2:6-20 -> 437:2-17', + '2:6-20 -> 438:2-17', + '2:6-20 -> 439:2-15', + '2:6-20 -> 440:2-15', + '2:6-20 -> 441:2-20', + '2:6-20 -> 442:2-40', + '2:6-20 -> 443:2-32', + '2:6-20 -> 444:2-31', + '2:6-20 -> 445:2-30', + '2:6-20 -> 446:2-17', + '2:6-20 -> 447:2-22', + '2:6-20 -> 448:2-24', + '2:6-20 -> 449:2-25', + '2:6-20 -> 450:2-26', + '2:6-20 -> 451:2-20', + '2:6-20 -> 452:2-29', + '2:6-20 -> 453:2-30', + '2:6-20 -> 454:2-40', + '2:6-20 -> 455:2-36', + '2:6-20 -> 456:2-29', + '2:6-20 -> 457:2-24', + '2:6-20 -> 458:2-32', + '2:6-20 -> 459:2-14', + '2:6-20 -> 460:2-20', + '2:6-20 -> 461:2-18', + '2:6-20 -> 462:2-19', + '2:6-20 -> 463:2-20', + '2:6-20 -> 464:2-16', + '2:6-20 -> 465:2-18', + '2:6-20 -> 466:2-15', + '2:6-20 -> 467:2-21', + '2:6-20 -> 468:2-23', + '2:6-20 -> 469:2-29', + '2:6-20 -> 470:2-27', + '2:6-20 -> 471:2-28', + '2:6-20 -> 472:2-29', + '2:6-20 -> 473:2-25', + '2:6-20 -> 474:2-26', + '2:6-20 -> 475:2-27', + '2:6 -> 476:2', + '2:20 -> 477:0', + ]) +}) + +test.skip('utilities have source maps', async () => { + let config = { + content: [{ raw: `text-red-500` }], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(1) + + expect(annotations).toStrictEqual(['2:6 -> 1:0', '2:6-25 -> 2:4-24', '2:6 -> 3:4', '2:25 -> 4:0']) +}) + +test.skip('components have source maps', async () => { + let config = { + content: [{ raw: `container` }], + } + + let input = css` + @tailwind components; + ` + + let result = await run(input, config) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(1) + + expect(annotations).toEqual([ + '2:6 -> 1:0', + '2:6 -> 2:4', + '2:26 -> 3:0', + '2:6 -> 4:0', + '2:6 -> 5:4', + '2:6 -> 6:8', + '2:26 -> 7:4', + '2:26 -> 8:0', + '2:6 -> 9:0', + '2:6 -> 10:4', + '2:6 -> 11:8', + '2:26 -> 12:4', + '2:26 -> 13:0', + '2:6 -> 14:0', + '2:6 -> 15:4', + '2:6 -> 16:8', + '2:26 -> 17:4', + '2:26 -> 18:0', + '2:6 -> 19:0', + '2:6 -> 20:4', + '2:6 -> 21:8', + '2:26 -> 22:4', + '2:26 -> 23:0', + '2:6 -> 24:0', + '2:6 -> 25:4', + '2:6 -> 26:8', + '2:26 -> 27:4', + '2:26 -> 28:0', + ]) +}) + +test.skip('source maps for layer rules are not rewritten to point to @tailwind directives', async () => { + let config = { + content: [{ raw: `font-normal foo hover:foo` }], + } + + let utilitiesFile = postcss.parse( + css` + @tailwind utilities; + `, + { from: 'components.css', map: { prev: map } } + ) + + let mainCssFile = postcss.parse( + css` + @layer utilities { + .foo { + background-color: red; + } + } + `, + { from: 'input.css', map: { prev: map } } + ) + + // Just pretend that there's an @import in `mainCssFile` that imports the nodes from `utilitiesFile` + let input = postcss.root({ + nodes: [...utilitiesFile.nodes, ...mainCssFile.nodes], + source: mainCssFile.source, + }) + + let result = await run(input, config) + + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + + // And we should see that the source map for the layer rule is not rewritten + // to point to the @tailwind directive but instead points to the original + expect(sources.length).toBe(2) + expect(sources).toEqual(['components.css', 'input.css']) + + expect(annotations).toEqual([ + '2:10 -> 1:0', + '2:10 -> 2:14', + '2:29 -> 3:0', + '3:12 -> 4:12', + '4:14-35 -> 5:14-35', + '5:12 -> 6:12', + '3:12 -> 7:12', + '4:14-35 -> 8:14-35', + '5:12 -> 9:12', + ]) }) diff --git a/tests/space-utilities.test.js b/tests/space-utilities.test.js new file mode 100644 index 000000000..fb027a337 --- /dev/null +++ b/tests/space-utilities.test.js @@ -0,0 +1,43 @@ +import { run, html, css, defaults } from './util/run' + +test('space-x uses non-logical properties', () => { + let config = { + future: { + logicalSiblingUtilities: false, + }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchCss(css` + ${defaults} + .space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-right: calc(1rem * var(--tw-space-x-reverse)); + margin-left: calc(1rem * calc(1 - var(--tw-space-x-reverse))); + } + `) + }) +}) + +test('space-x uses logical properties', () => { + let config = { + future: { + logicalSiblingUtilities: true, + }, + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base; @tailwind utilities;', config).then((result) => { + expect(result.css).toMatchCss(css` + ${defaults} + .space-x-4 > :not([hidden]) ~ :not([hidden]) { + --tw-space-x-reverse: 0; + margin-inline-start: calc(1rem * calc(1 - var(--tw-space-x-reverse))); + margin-inline-end: calc(1rem * var(--tw-space-x-reverse)); + } + `) + }) +}) diff --git a/tests/syntax-lit-html.test.js b/tests/syntax-lit-html.test.js index 952a9b969..a3bdfebda 100644 --- a/tests/syntax-lit-html.test.js +++ b/tests/syntax-lit-html.test.js @@ -1,72 +1,45 @@ -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(({ stable, oxide }) => { - test('it detects classes in lit-html templates', () => { - let config = { - content: [ - { - raw: `html\`\`;`, - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], - } +test('it detects classes in lit-html templates', () => { + let config = { + content: [ + { + raw: `html\`\`;`, + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .rounded { - border-radius: 0.25rem; - } - .bg-blue-400 { - --tw-bg-opacity: 1; - background-color: rgb(96 165 250 / var(--tw-bg-opacity)); - } - .px-4 { - padding-left: 1rem; - padding-right: 1rem; - } - .py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; - } - .font-bold { - font-weight: 700; - } - .text-white { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); - } - .hover\:bg-blue-600:hover { - --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .rounded { - border-radius: 0.25rem; - } - .bg-blue-400 { - background-color: #60a5fa; - } - .px-4 { - padding-left: 1rem; - padding-right: 1rem; - } - .py-2 { - padding-top: 0.5rem; - padding-bottom: 0.5rem; - } - .font-bold { - font-weight: 700; - } - .text-white { - color: #fff; - } - .hover\:bg-blue-600:hover { - background-color: #2563eb; - } - `) - }) + return run('@tailwind utilities', config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .rounded { + border-radius: 0.25rem; + } + .bg-blue-400 { + --tw-bg-opacity: 1; + background-color: rgb(96 165 250 / var(--tw-bg-opacity)); + } + .px-4 { + padding-left: 1rem; + padding-right: 1rem; + } + .py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; + } + .font-bold { + font-weight: 700; + } + .text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } + .hover\:bg-blue-600:hover { + --tw-bg-opacity: 1; + background-color: rgb(37 99 235 / var(--tw-bg-opacity)); + } + `) }) }) diff --git a/tests/syntax-svelte.test.js b/tests/syntax-svelte.test.js index be2c33e8b..8acd91a5b 100644 --- a/tests/syntax-svelte.test.js +++ b/tests/syntax-svelte.test.js @@ -1,43 +1,40 @@ import path from 'path' -import { crosscheck, run, css } from './util/run' +import { run, css } from './util/run' -crosscheck(({ stable, oxide }) => { - oxide.test.todo('it detects svelte based on the file extension') - stable.test('it detects svelte based on the file extension', () => { - let config = { - content: [path.resolve(__dirname, './syntax-svelte.test.svelte')], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], - } +test('it detects svelte based on the file extension', () => { + let config = { + content: [path.resolve(__dirname, './syntax-svelte.test.svelte')], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .bg-red-500 { + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + @media (min-width: 1024px) { + .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } - @media (min-width: 1024px) { - .lg\:hover\:bg-blue-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - } - } - `) - }) + } + `) }) +}) - oxide.test.todo('using raw with svelte extension') - stable.test('using raw with svelte extension', () => { - let config = { - content: [ - { - raw: ` +test('using raw with svelte extension', () => { + let config = { + content: [ + { + raw: ` @@ -50,32 +47,31 @@ crosscheck(({ stable, oxide }) => { Click me `, - extension: 'svelte', - }, - ], - corePlugins: { preflight: false }, - theme: {}, - plugins: [], - } + extension: 'svelte', + }, + ], + corePlugins: { preflight: false }, + theme: {}, + plugins: [], + } - let input = css` - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` - .bg-red-500 { + return run(input, config).then((result) => { + expect(result.css).toMatchCss(css` + .bg-red-500 { + --tw-bg-opacity: 1; + background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + } + @media (min-width: 1024px) { + .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); + background-color: rgb(59 130 246 / var(--tw-bg-opacity)); } - @media (min-width: 1024px) { - .lg\:hover\:bg-blue-500:hover { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); - } - } - `) - }) + } + `) }) }) diff --git a/tests/tailwind-screens.test.js b/tests/tailwind-screens.test.js index f968fd0e3..009c02bc3 100644 --- a/tests/tailwind-screens.test.js +++ b/tests/tailwind-screens.test.js @@ -1,65 +1,63 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(() => { - test('class variants are inserted at `@tailwind variants`', async () => { - let config = { - content: [{ raw: html`
` }], +test('class variants are inserted at `@tailwind variants`', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + @tailwind variants; + .foo { + color: black; } + ` - let input = css` - @tailwind utilities; - @tailwind variants; - .foo { - color: black; + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold, + .hover\:font-bold:hover { + font-weight: 700; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold, - .hover\:font-bold:hover { + @media (min-width: 768px) { + .md\:font-bold { font-weight: 700; } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - .foo { - color: #000; - } - `) - }) - }) - - test('`@tailwind screens` works as an alias for `@tailwind variants`', async () => { - let config = { - content: [{ raw: html`
` }], - } - - let input = css` - @tailwind utilities; - @tailwind screens; - .foo { - color: black; } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .font-bold, - .hover\:font-bold:hover { - font-weight: 700; - } - @media (min-width: 768px) { - .md\:font-bold { - font-weight: 700; - } - } - .foo { - color: #000; - } - `) - }) + .foo { + color: #000; + } + `) + }) +}) + +test('`@tailwind screens` works as an alias for `@tailwind variants`', async () => { + let config = { + content: [{ raw: html`
` }], + } + + let input = css` + @tailwind utilities; + @tailwind screens; + .foo { + color: black; + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .font-bold, + .hover\:font-bold:hover { + font-weight: 700; + } + @media (min-width: 768px) { + .md\:font-bold { + font-weight: 700; + } + } + .foo { + color: #000; + } + `) }) }) diff --git a/tests/to-path.test.js b/tests/to-path.test.js index 1e6021ba9..8737194ed 100644 --- a/tests/to-path.test.js +++ b/tests/to-path.test.js @@ -1,21 +1,18 @@ import { toPath } from '../src/util/toPath' -import { crosscheck } from './util/run' -crosscheck(() => { - it('should keep an array as an array', () => { - let input = ['a', 'b', '0', 'c'] +it('should keep an array as an array', () => { + let input = ['a', 'b', '0', 'c'] - expect(toPath(input)).toBe(input) - }) - - it.each` - input | output - ${'a.b.c'} | ${['a', 'b', 'c']} - ${'a[0].b.c'} | ${['a', '0', 'b', 'c']} - ${'.a'} | ${['a']} - ${'[].a'} | ${['a']} - ${'a[1.5][b][c]'} | ${['a', '1.5', 'b', 'c']} - `('should convert "$input" to "$output"', ({ input, output }) => { - expect(toPath(input)).toEqual(output) - }) + expect(toPath(input)).toBe(input) +}) + +it.each` + input | output + ${'a.b.c'} | ${['a', 'b', 'c']} + ${'a[0].b.c'} | ${['a', '0', 'b', 'c']} + ${'.a'} | ${['a']} + ${'[].a'} | ${['a']} + ${'a[1.5][b][c]'} | ${['a', '1.5', 'b', 'c']} +`('should convert "$input" to "$output"', ({ input, output }) => { + expect(toPath(input)).toEqual(output) }) diff --git a/tests/util/apply-important-selector.test.js b/tests/util/apply-important-selector.test.js index 0ec22792f..ab9842d83 100644 --- a/tests/util/apply-important-selector.test.js +++ b/tests/util/apply-important-selector.test.js @@ -1,24 +1,21 @@ -import { crosscheck } from '../util/run' import { applyImportantSelector } from '../../src/util/applyImportantSelector' -crosscheck(() => { - it.each` - before | after - ${'.foo'} | ${'#app :is(.foo)'} - ${'.foo .bar'} | ${'#app :is(.foo .bar)'} - ${'.foo:hover'} | ${'#app :is(.foo:hover)'} - ${'.foo .bar:hover'} | ${'#app :is(.foo .bar:hover)'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::before'} | ${'#app :is(.foo)::before'} - ${'.foo::file-selector-button'} | ${'#app :is(.foo)::file-selector-button'} - ${'.foo::-webkit-progress-bar'} | ${'#app :is(.foo)::-webkit-progress-bar'} - ${'.foo:hover::before'} | ${'#app :is(.foo:hover)::before'} - ${':is(.dark :is([dir="rtl"] .foo::before))'} | ${'#app :is(.dark :is([dir="rtl"] .foo))::before'} - ${':is(.dark .foo) .bar'} | ${'#app :is(:is(.dark .foo) .bar)'} - ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} - ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} - ${'.foo:before'} | ${'#app :is(.foo):before'} - `('should generate "$after" from "$before"', ({ before, after }) => { - expect(applyImportantSelector(before, '#app')).toEqual(after) - }) +it.each` + before | after + ${'.foo'} | ${'#app :is(.foo)'} + ${'.foo .bar'} | ${'#app :is(.foo .bar)'} + ${'.foo:hover'} | ${'#app :is(.foo:hover)'} + ${'.foo .bar:hover'} | ${'#app :is(.foo .bar:hover)'} + ${'.foo::before'} | ${'#app :is(.foo)::before'} + ${'.foo::before'} | ${'#app :is(.foo)::before'} + ${'.foo::file-selector-button'} | ${'#app :is(.foo)::file-selector-button'} + ${'.foo::-webkit-progress-bar'} | ${'#app :is(.foo)::-webkit-progress-bar'} + ${'.foo:hover::before'} | ${'#app :is(.foo:hover)::before'} + ${':is(.dark :is([dir="rtl"] .foo::before))'} | ${'#app :is(.dark :is([dir="rtl"] .foo))::before'} + ${':is(.dark .foo) .bar'} | ${'#app :is(:is(.dark .foo) .bar)'} + ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} + ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} + ${'.foo:before'} | ${'#app :is(.foo):before'} +`('should generate "$after" from "$before"', ({ before, after }) => { + expect(applyImportantSelector(before, '#app')).toEqual(after) }) diff --git a/tests/util/crosscheck.test.js b/tests/util/crosscheck.test.js deleted file mode 100644 index 032473386..000000000 --- a/tests/util/crosscheck.test.js +++ /dev/null @@ -1,18 +0,0 @@ -import { crosscheck } from './run' - -crosscheck(({ stable, oxide, engine }) => { - stable.test('should run on stable', () => { - expect(engine.stable).toBe(true) - expect(engine.oxide).toBe(false) - }) - oxide.test('should run on oxide', () => { - expect(engine.stable).toBe(false) - expect(engine.oxide).toBe(true) - }) - test('should run on both', () => { - oxide.expect(engine.oxide).toBe(true) - oxide.expect(engine.stable).toBe(false) - stable.expect(engine.oxide).toBe(false) - stable.expect(engine.stable).toBe(true) - }) -}) diff --git a/tests/util/run.js b/tests/util/run.js index 964d5d5f5..08dbc3b80 100644 --- a/tests/util/run.js +++ b/tests/util/run.js @@ -1,7 +1,6 @@ import path from 'path' import postcss from 'postcss' import tailwind from '../../src' -import { env } from '../../src/lib/sharedState' export * from './strings' export * from './defaults' @@ -14,8 +13,6 @@ export let map = JSON.stringify({ mappings: '', }) -globalThis.__OXIDE__ = env.ENGINE === 'oxide' - export function run(input, config, plugin = tailwind) { let { currentTestName, testPath } = expect.getState() @@ -34,61 +31,3 @@ export function runWithSourceMaps(input, config, plugin = tailwind) { }, }) } - -let nullTest = Object.assign(function () {}, { - skip: () => {}, - only: () => {}, - each: () => () => {}, - todo: () => {}, -}) -let nullProxy = new Proxy( - { - test: nullTest, - it: nullTest, - xit: nullTest.skip, - fit: nullTest.only, - xdescribe: nullTest.skip, - fdescribe: nullTest.only, - }, - { - get(target, prop, _receiver) { - if (prop in target) { - return target[prop] - } - return Object.assign(() => { - return nullProxy - }, nullProxy) - }, - } -) - -/** - * @typedef {object} CrossCheck - * @property {typeof import('@jest/globals')} oxide - * @property {typeof import('@jest/globals')} stable - * @property {object} engine - * @property {boolean} engine.oxide - * @property {boolean} engine.stable - */ - -/** - * @param {(data: CrossCheck) => void} fn - */ -export function crosscheck(fn) { - let engines = - env.ENGINE === 'oxide' ? [{ engine: 'Stable' }, { engine: 'Oxide' }] : [{ engine: 'Stable' }] - - describe.each(engines)('$engine', ({ engine }) => { - let engines = { - oxide: engine === 'Oxide' ? globalThis : nullProxy, - stable: engine === 'Stable' ? globalThis : nullProxy, - engine: { oxide: engine === 'Oxide', stable: engine === 'Stable' }, - } - - beforeEach(() => { - globalThis.__OXIDE__ = engines.engine.oxide - }) - - fn(engines) - }) -} diff --git a/tests/variants.oxide.test.css b/tests/variants.oxide.test.css deleted file mode 100644 index 5e06f3942..000000000 --- a/tests/variants.oxide.test.css +++ /dev/null @@ -1,412 +0,0 @@ -*, -:before, -:after, -::backdrop { - --tw-border-spacing-x: 0; - --tw-border-spacing-y: 0; - --tw-translate-x: 0; - --tw-translate-y: 0; - --tw-rotate: 0; - --tw-skew-x: 0; - --tw-skew-y: 0; - --tw-scale-x: 1; - --tw-scale-y: 1; - --tw-pan-x: ; - --tw-pan-y: ; - --tw-pinch-zoom: ; - --tw-scroll-snap-strictness: proximity; - --tw-gradient-from-position: ; - --tw-gradient-via-position: ; - --tw-gradient-to-position: ; - --tw-ordinal: ; - --tw-slashed-zero: ; - --tw-numeric-figure: ; - --tw-numeric-spacing: ; - --tw-numeric-fraction: ; - --tw-ring-inset: ; - --tw-ring-offset-width: 0px; - --tw-ring-offset-color: #fff; - --tw-ring-color: #3b82f680; - --tw-ring-offset-shadow: 0 0 #0000; - --tw-ring-shadow: 0 0 #0000; - --tw-shadow: 0 0 #0000; - --tw-shadow-colored: 0 0 #0000; - --tw-blur: ; - --tw-brightness: ; - --tw-contrast: ; - --tw-grayscale: ; - --tw-hue-rotate: ; - --tw-invert: ; - --tw-saturate: ; - --tw-sepia: ; - --tw-drop-shadow: ; - --tw-backdrop-blur: ; - --tw-backdrop-brightness: ; - --tw-backdrop-contrast: ; - --tw-backdrop-grayscale: ; - --tw-backdrop-hue-rotate: ; - --tw-backdrop-invert: ; - --tw-backdrop-opacity: ; - --tw-backdrop-saturate: ; - --tw-backdrop-sepia: ; -} -.first-letter\:text-2xl:first-letter { - font-size: 1.5rem; - line-height: 2rem; -} -.first-letter\:text-red-500:first-letter { - color: #ef4444; -} -.first-line\:bg-yellow-300:first-line { - background-color: #fde047; -} -.first-line\:underline:first-line { - text-decoration-line: underline; -} -.marker\:text-lg ::marker { - font-size: 1.125rem; - line-height: 1.75rem; -} -.marker\:text-red-500 ::marker { - color: #ef4444; -} -.marker\:text-lg::marker { - font-size: 1.125rem; - line-height: 1.75rem; -} -.marker\:text-red-500::marker { - color: #ef4444; -} -.selection\:bg-blue-500 ::selection { - background-color: #3b82f6; -} -.selection\:text-white ::selection { - color: #fff; -} -.selection\:bg-blue-500::selection { - background-color: #3b82f6; -} -.selection\:text-white::selection { - color: #fff; -} -.file\:bg-blue-500::file-selector-button { - background-color: #3b82f6; -} -.file\:text-white::file-selector-button { - color: #fff; -} -.placeholder\:font-bold::placeholder { - font-weight: 700; -} -.placeholder\:text-red-500::placeholder { - color: #ef4444; -} -.backdrop\:shadow-md::backdrop { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.before\:block:before { - content: var(--tw-content); - display: block; -} -.before\:bg-red-500:before { - content: var(--tw-content); - background-color: #ef4444; -} -.after\:flex:after { - content: var(--tw-content); - display: flex; -} -.after\:uppercase:after { - content: var(--tw-content); - text-transform: uppercase; -} -.first\:shadow-md:first-child, -.last\:shadow-md:last-child, -.only\:shadow-md:only-child, -.odd\:shadow-md:nth-child(2n + 1), -.even\:shadow-md:nth-child(2n), -.first-of-type\:shadow-md:first-of-type, -.last-of-type\:shadow-md:last-of-type, -.only-of-type\:shadow-md:only-of-type, -.visited\:shadow-md:visited, -.target\:shadow-md:target { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.open\:bg-red-200[open] { - background-color: #fecaca; -} -.default\:shadow-md:default, -.checked\:shadow-md:checked, -.indeterminate\:shadow-md:indeterminate, -.placeholder-shown\:shadow-md:placeholder-shown, -.autofill\:shadow-md:autofill, -.optional\:shadow-md:optional, -.required\:shadow-md:required, -.valid\:shadow-md:valid, -.invalid\:shadow-md:invalid, -.in-range\:shadow-md:in-range, -.out-of-range\:shadow-md:out-of-range, -.read-only\:shadow-md:read-only, -.empty\:shadow-md:empty, -.focus-within\:shadow-md:focus-within { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -@keyframes spin { - to { - transform: rotate(360deg); - } -} -.hover\:animate-spin:hover { - animation: 1s linear infinite spin; -} -.hover\:shadow-md:hover { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.file\:hover\:bg-blue-600:hover::file-selector-button { - background-color: #2563eb; -} -.open\:hover\:bg-red-200:hover[open] { - background-color: #fecaca; -} -.focus\:shadow-md:focus, -.focus\:hover\:shadow-md:hover:focus, -.focus-visible\:shadow-md:focus-visible, -.active\:shadow-md:active, -.enabled\:shadow-md:enabled, -.disabled\:shadow-md:disabled, -.group:first-child .group-first\:shadow-md, -.group:last-child .group-last\:shadow-md, -.group:only-child .group-only\:shadow-md, -.group:nth-child(2n + 1) .group-odd\:shadow-md, -.group:nth-child(2n) .group-even\:shadow-md, -.group:first-of-type .group-first-of-type\:shadow-md, -.group:last-of-type .group-last-of-type\:shadow-md, -.group:only-of-type .group-only-of-type\:shadow-md, -.group:visited .group-visited\:shadow-md, -.group:target .group-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open] .group-open\:bg-red-200 { - background-color: #fecaca; -} -.group:default .group-default\:shadow-md, -.group:checked .group-checked\:shadow-md, -.group:indeterminate .group-indeterminate\:shadow-md, -.group:placeholder-shown .group-placeholder-shown\:shadow-md, -.group:autofill .group-autofill\:shadow-md, -.group:optional .group-optional\:shadow-md, -.group:required .group-required\:shadow-md, -.group:valid .group-valid\:shadow-md, -.group:invalid .group-invalid\:shadow-md, -.group:in-range .group-in-range\:shadow-md, -.group:out-of-range .group-out-of-range\:shadow-md, -.group:read-only .group-read-only\:shadow-md, -.group:empty .group-empty\:shadow-md, -.group:focus-within .group-focus-within\:shadow-md, -.group:hover .group-hover\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:hover .group-open\:group-hover\:space-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-inline-start: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); - margin-inline-end: calc(0.5rem * var(--tw-space-x-reverse)); -} -.group:focus .group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:focus .group-open\:group-focus\:bg-red-200 { - background-color: #fecaca; -} -.group:focus:hover .group-focus\:group-hover\:shadow-md, -.group:focus-visible .group-focus-visible\:shadow-md, -.group:active .group-active\:shadow-md, -.group:enabled .group-enabled\:shadow-md, -.group:disabled .group-disabled\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:shadow-md:first-child, -.peer:first-child ~ .peer-first\:shadow-md, -.peer:last-child ~ .peer-last\:shadow-md, -.peer:only-child ~ .peer-only\:shadow-md, -.peer:nth-child(2n + 1) ~ .peer-odd\:shadow-md, -.peer:nth-child(2n) ~ .peer-even\:shadow-md, -.peer:first-of-type ~ .peer-first-of-type\:shadow-md, -.peer:last-of-type ~ .peer-last-of-type\:shadow-md, -.peer:only-of-type ~ .peer-only-of-type\:shadow-md, -.peer:visited ~ .peer-visited\:shadow-md, -.peer:target ~ .peer-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.peer[open] ~ .peer-open\:bg-red-200 { - background-color: #fecaca; -} -.peer:default ~ .peer-default\:shadow-md, -.peer:checked ~ .peer-checked\:shadow-md, -.peer:indeterminate ~ .peer-indeterminate\:shadow-md, -.peer:placeholder-shown ~ .peer-placeholder-shown\:shadow-md, -.peer:autofill ~ .peer-autofill\:shadow-md, -.peer:optional ~ .peer-optional\:shadow-md, -.peer:required ~ .peer-required\:shadow-md, -.peer:valid ~ .peer-valid\:shadow-md, -.peer:invalid ~ .peer-invalid\:shadow-md, -.peer:in-range ~ .peer-in-range\:shadow-md, -.peer:out-of-range ~ .peer-out-of-range\:shadow-md, -.peer:read-only ~ .peer-read-only\:shadow-md, -.peer:empty ~ .peer-empty\:shadow-md, -.peer:focus-within ~ .peer-focus-within\:shadow-md, -.peer:hover ~ .peer-hover\:shadow-md, -.peer:focus ~ .peer-focus\:shadow-md, -.peer:focus:hover ~ .peer-focus\:peer-hover\:shadow-md, -.peer:focus-visible ~ .peer-focus-visible\:shadow-md, -.peer:active ~ .peer-active\:shadow-md, -.peer:enabled ~ .peer-enabled\:shadow-md, -.peer:disabled ~ .peer-disabled\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:shadow-md:first-child, -:is([dir='ltr'] .ltr\:shadow-md), -:is([dir='rtl'] .rtl\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -@media (prefers-reduced-motion: no-preference) { - .motion-safe\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (prefers-reduced-motion: reduce) { - .motion-reduce\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (prefers-contrast: more) { - .contrast-more\:bg-yellow-300 { - background-color: #fde047; - } -} -@media (prefers-contrast: less) { - .contrast-less\:bg-yellow-300 { - background-color: #fde047; - } -} -:is(.dark .dark\:shadow-md), -:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md), -:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -@media print { - .print\:bg-yellow-300 { - background-color: #fde047; - } -} -@media (min-width: 640px) { - .sm\:shadow-md, - .sm\:active\:shadow-md:active { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 768px) { - .md\:shadow-md, - .group:focus .md\:group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 1024px) { - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .lg\:animate-spin { - animation: 1s linear infinite spin; - } - .lg\:shadow-md, - :is(.dark .lg\:dark\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 1280px) { - .xl\:shadow-md, - :is(.dark .xl\:dark\:disabled\:shadow-md:disabled) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } -} -@media (min-width: 1536px) { - .\32 xl\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - @media (prefers-reduced-motion: no-preference) { - :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); - } - } -} -@media (orientation: portrait) { - .portrait\:bg-yellow-300 { - background-color: #fde047; - } -} -@media (orientation: landscape) { - .landscape\:bg-yellow-300 { - background-color: #fde047; - } -} diff --git a/tests/variants.test.css b/tests/variants.test.css index 8a9d481ee..2bb486303 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -50,384 +50,209 @@ --tw-backdrop-saturate: ; --tw-backdrop-sepia: ; } -.first-letter\:text-2xl:first-letter { - font-size: 1.5rem; - line-height: 2rem; +.first-letter\:flex:first-letter, +.first-line\:flex:first-line, +.marker\:flex ::marker, +.marker\:flex::marker, +.selection\:flex ::selection, +.selection\:flex::selection { + display: flex; } -.first-letter\:text-red-500:first-letter { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); +.file\:flex::file-selector-button { + display: flex; } -.first-line\:bg-yellow-300:first-line { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); -} -.first-line\:underline:first-line { - text-decoration-line: underline; -} -.marker\:text-lg ::marker { - font-size: 1.125rem; - line-height: 1.75rem; -} -.marker\:text-red-500 ::marker { - color: #ef4444; -} -.marker\:text-lg::marker { - font-size: 1.125rem; - line-height: 1.75rem; -} -.marker\:text-red-500::marker { - color: #ef4444; -} -.selection\:bg-blue-500 ::selection { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); -} -.selection\:text-white ::selection { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} -.selection\:bg-blue-500::selection { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); -} -.selection\:text-white::selection { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} -.file\:bg-blue-500::file-selector-button { - --tw-bg-opacity: 1; - background-color: rgb(59 130 246 / var(--tw-bg-opacity)); -} -.file\:text-white::file-selector-button { - --tw-text-opacity: 1; - color: rgb(255 255 255 / var(--tw-text-opacity)); -} -.placeholder\:font-bold::placeholder { - font-weight: 700; -} -.placeholder\:text-red-500::placeholder { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); -} -.backdrop\:shadow-md::backdrop { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.before\:block:before { - content: var(--tw-content); - display: block; -} -.before\:bg-red-500:before { - content: var(--tw-content); - --tw-bg-opacity: 1; - background-color: rgb(239 68 68 / var(--tw-bg-opacity)); +.placeholder\:flex::placeholder, +.backdrop\:flex::backdrop { + display: flex; } +.before\:flex:before, .after\:flex:after { content: var(--tw-content); display: flex; } -.after\:uppercase:after { - content: var(--tw-content); - text-transform: uppercase; +.first\:flex:first-child, +.last\:flex:last-child, +.only\:flex:only-child, +.odd\:flex:nth-child(2n + 1), +.even\:flex:nth-child(2n), +.first-of-type\:flex:first-of-type, +.last-of-type\:flex:last-of-type, +.only-of-type\:flex:only-of-type, +.visited\:flex:visited, +.target\:flex:target, +.open\:flex[open], +.default\:flex:default, +.checked\:flex:checked, +.indeterminate\:flex:indeterminate, +.placeholder-shown\:flex:placeholder-shown, +.autofill\:flex:autofill, +.optional\:flex:optional, +.required\:flex:required, +.valid\:flex:valid, +.invalid\:flex:invalid, +.in-range\:flex:in-range, +.out-of-range\:flex:out-of-range, +.read-only\:flex:read-only, +.empty\:flex:empty, +.focus-within\:flex:focus-within, +.hover\:flex:hover { + display: flex; } -.first\:shadow-md:first-child, -.last\:shadow-md:last-child, -.only\:shadow-md:only-child, -.odd\:shadow-md:nth-child(2n + 1), -.even\:shadow-md:nth-child(2n), -.first-of-type\:shadow-md:first-of-type, -.last-of-type\:shadow-md:last-of-type, -.only-of-type\:shadow-md:only-of-type, -.visited\:shadow-md:visited, -.target\:shadow-md:target { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +.file\:hover\:flex:hover::file-selector-button { + display: flex; } -.open\:bg-red-200[open] { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.default\:shadow-md:default, -.checked\:shadow-md:checked, -.indeterminate\:shadow-md:indeterminate, -.placeholder-shown\:shadow-md:placeholder-shown, -.autofill\:shadow-md:autofill, -.optional\:shadow-md:optional, -.required\:shadow-md:required, -.valid\:shadow-md:valid, -.invalid\:shadow-md:invalid, -.in-range\:shadow-md:in-range, -.out-of-range\:shadow-md:out-of-range, -.read-only\:shadow-md:read-only, -.empty\:shadow-md:empty, -.focus-within\:shadow-md:focus-within { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -@keyframes spin { - to { - transform: rotate(360deg); - } -} -.hover\:animate-spin:hover { - animation: 1s linear infinite spin; -} -.hover\:shadow-md:hover { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.file\:hover\:bg-blue-600:hover::file-selector-button { - --tw-bg-opacity: 1; - background-color: rgb(37 99 235 / var(--tw-bg-opacity)); -} -.open\:hover\:bg-red-200:hover[open] { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.focus\:shadow-md:focus, -.focus\:hover\:shadow-md:hover:focus, -.focus-visible\:shadow-md:focus-visible, -.active\:shadow-md:active, -.enabled\:shadow-md:enabled, -.disabled\:shadow-md:disabled, -.group:first-child .group-first\:shadow-md, -.group:last-child .group-last\:shadow-md, -.group:only-child .group-only\:shadow-md, -.group:nth-child(2n + 1) .group-odd\:shadow-md, -.group:nth-child(2n) .group-even\:shadow-md, -.group:first-of-type .group-first-of-type\:shadow-md, -.group:last-of-type .group-last-of-type\:shadow-md, -.group:only-of-type .group-only-of-type\:shadow-md, -.group:visited .group-visited\:shadow-md, -.group:target .group-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open] .group-open\:bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.group:default .group-default\:shadow-md, -.group:checked .group-checked\:shadow-md, -.group:indeterminate .group-indeterminate\:shadow-md, -.group:placeholder-shown .group-placeholder-shown\:shadow-md, -.group:autofill .group-autofill\:shadow-md, -.group:optional .group-optional\:shadow-md, -.group:required .group-required\:shadow-md, -.group:valid .group-valid\:shadow-md, -.group:invalid .group-invalid\:shadow-md, -.group:in-range .group-in-range\:shadow-md, -.group:out-of-range .group-out-of-range\:shadow-md, -.group:read-only .group-read-only\:shadow-md, -.group:empty .group-empty\:shadow-md, -.group:focus-within .group-focus-within\:shadow-md, -.group:hover .group-hover\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:hover .group-open\:group-hover\:space-x-2 > :not([hidden]) ~ :not([hidden]) { - --tw-space-x-reverse: 0; - margin-right: calc(0.5rem * var(--tw-space-x-reverse)); - margin-left: calc(0.5rem * calc(1 - var(--tw-space-x-reverse))); -} -.group:focus .group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.group[open]:focus .group-open\:group-focus\:bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.group:focus:hover .group-focus\:group-hover\:shadow-md, -.group:focus-visible .group-focus-visible\:shadow-md, -.group:active .group-active\:shadow-md, -.group:enabled .group-enabled\:shadow-md, -.group:disabled .group-disabled\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:shadow-md, -.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:shadow-md:first-child, -.peer:first-child ~ .peer-first\:shadow-md, -.peer:last-child ~ .peer-last\:shadow-md, -.peer:only-child ~ .peer-only\:shadow-md, -.peer:nth-child(2n + 1) ~ .peer-odd\:shadow-md, -.peer:nth-child(2n) ~ .peer-even\:shadow-md, -.peer:first-of-type ~ .peer-first-of-type\:shadow-md, -.peer:last-of-type ~ .peer-last-of-type\:shadow-md, -.peer:only-of-type ~ .peer-only-of-type\:shadow-md, -.peer:visited ~ .peer-visited\:shadow-md, -.peer:target ~ .peer-target\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); -} -.peer[open] ~ .peer-open\:bg-red-200 { - --tw-bg-opacity: 1; - background-color: rgb(254 202 202 / var(--tw-bg-opacity)); -} -.peer:default ~ .peer-default\:shadow-md, -.peer:checked ~ .peer-checked\:shadow-md, -.peer:indeterminate ~ .peer-indeterminate\:shadow-md, -.peer:placeholder-shown ~ .peer-placeholder-shown\:shadow-md, -.peer:autofill ~ .peer-autofill\:shadow-md, -.peer:optional ~ .peer-optional\:shadow-md, -.peer:required ~ .peer-required\:shadow-md, -.peer:valid ~ .peer-valid\:shadow-md, -.peer:invalid ~ .peer-invalid\:shadow-md, -.peer:in-range ~ .peer-in-range\:shadow-md, -.peer:out-of-range ~ .peer-out-of-range\:shadow-md, -.peer:read-only ~ .peer-read-only\:shadow-md, -.peer:empty ~ .peer-empty\:shadow-md, -.peer:focus-within ~ .peer-focus-within\:shadow-md, -.peer:hover ~ .peer-hover\:shadow-md, -.peer:focus ~ .peer-focus\:shadow-md, -.peer:focus:hover ~ .peer-focus\:peer-hover\:shadow-md, -.peer:focus-visible ~ .peer-focus-visible\:shadow-md, -.peer:active ~ .peer-active\:shadow-md, -.peer:enabled ~ .peer-enabled\:shadow-md, -.peer:disabled ~ .peer-disabled\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:shadow-md, -.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:shadow-md:first-child, -:is([dir='ltr'] .ltr\:shadow-md), -:is([dir='rtl'] .rtl\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +.open\:hover\:flex:hover[open], +.focus\:flex:focus, +.focus\:hover\:flex:hover:focus, +.focus-visible\:flex:focus-visible, +.active\:flex:active, +.enabled\:flex:enabled, +.disabled\:flex:disabled, +.group:first-child .group-first\:flex, +.group:last-child .group-last\:flex, +.group:only-child .group-only\:flex, +.group:nth-child(2n + 1) .group-odd\:flex, +.group:nth-child(2n) .group-even\:flex, +.group:first-of-type .group-first-of-type\:flex, +.group:last-of-type .group-last-of-type\:flex, +.group:only-of-type .group-only-of-type\:flex, +.group:visited .group-visited\:flex, +.group:target .group-target\:flex, +.group[open] .group-open\:flex, +.group:default .group-default\:flex, +.group:checked .group-checked\:flex, +.group:indeterminate .group-indeterminate\:flex, +.group:placeholder-shown .group-placeholder-shown\:flex, +.group:autofill .group-autofill\:flex, +.group:optional .group-optional\:flex, +.group:required .group-required\:flex, +.group:valid .group-valid\:flex, +.group:invalid .group-invalid\:flex, +.group:in-range .group-in-range\:flex, +.group:out-of-range .group-out-of-range\:flex, +.group:read-only .group-read-only\:flex, +.group:empty .group-empty\:flex, +.group:focus-within .group-focus-within\:flex, +.group:hover .group-hover\:flex, +.group[open]:hover .group-open\:group-hover\:flex, +.group:focus .group-focus\:flex, +.group[open]:focus .group-open\:group-focus\:flex, +.group:focus:hover .group-focus\:group-hover\:flex, +.group:focus-visible .group-focus-visible\:flex, +.group:active .group-active\:flex, +.group:enabled .group-enabled\:flex, +.group:disabled .group-disabled\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:flex:first-child, +.peer:first-child ~ .peer-first\:flex, +.peer:last-child ~ .peer-last\:flex, +.peer:only-child ~ .peer-only\:flex, +.peer:nth-child(2n + 1) ~ .peer-odd\:flex, +.peer:nth-child(2n) ~ .peer-even\:flex, +.peer:first-of-type ~ .peer-first-of-type\:flex, +.peer:last-of-type ~ .peer-last-of-type\:flex, +.peer:only-of-type ~ .peer-only-of-type\:flex, +.peer:visited ~ .peer-visited\:flex, +.peer:target ~ .peer-target\:flex, +.peer[open] ~ .peer-open\:flex, +.peer:default ~ .peer-default\:flex, +.peer:checked ~ .peer-checked\:flex, +.peer:indeterminate ~ .peer-indeterminate\:flex, +.peer:placeholder-shown ~ .peer-placeholder-shown\:flex, +.peer:autofill ~ .peer-autofill\:flex, +.peer:optional ~ .peer-optional\:flex, +.peer:required ~ .peer-required\:flex, +.peer:valid ~ .peer-valid\:flex, +.peer:invalid ~ .peer-invalid\:flex, +.peer:in-range ~ .peer-in-range\:flex, +.peer:out-of-range ~ .peer-out-of-range\:flex, +.peer:read-only ~ .peer-read-only\:flex, +.peer:empty ~ .peer-empty\:flex, +.peer:focus-within ~ .peer-focus-within\:flex, +.peer:hover ~ .peer-hover\:flex, +.peer:focus ~ .peer-focus\:flex, +.peer:focus:hover ~ .peer-focus\:peer-hover\:flex, +.peer:focus-visible ~ .peer-focus-visible\:flex, +.peer:active ~ .peer-active\:flex, +.peer:enabled ~ .peer-enabled\:flex, +.peer:disabled ~ .peer-disabled\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:flex:first-child, +:is([dir='ltr'] .ltr\:flex), +:is([dir='rtl'] .rtl\:flex) { + display: flex; } @media (prefers-reduced-motion: no-preference) { - .motion-safe\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .motion-safe\:flex { + display: flex; } } @media (prefers-reduced-motion: reduce) { - .motion-reduce\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .motion-reduce\:flex { + display: flex; } } @media (prefers-contrast: more) { - .contrast-more\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .contrast-more\:flex { + display: flex; } } @media (prefers-contrast: less) { - .contrast-less\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .contrast-less\:flex { + display: flex; } } -:is(.dark .dark\:shadow-md), -:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:shadow-md), -:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); +:is(.dark .dark\:flex), +:is(.dark .group:disabled:focus:hover .dark\:group-disabled\:group-focus\:group-hover\:flex), +:is(.dark .peer:disabled:focus:hover ~ .dark\:peer-disabled\:peer-focus\:peer-hover\:flex) { + display: flex; } @media print { - .print\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .print\:flex { + display: flex; } } @media (min-width: 640px) { - .sm\:shadow-md, - .sm\:active\:shadow-md:active { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .sm\:flex, + .sm\:active\:flex:active { + display: flex; } } @media (min-width: 768px) { - .md\:shadow-md, - .group:focus .md\:group-focus\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .md\:flex, + .group:focus .md\:group-focus\:flex { + display: flex; } } @media (min-width: 1024px) { - @keyframes spin { - to { - transform: rotate(360deg); - } - } - .lg\:animate-spin { - animation: 1s linear infinite spin; - } - .lg\:shadow-md, - :is(.dark .lg\:dark\:shadow-md) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .lg\:flex, + :is(.dark .lg\:dark\:flex) { + display: flex; } } @media (min-width: 1280px) { - .xl\:shadow-md, - :is(.dark .xl\:dark\:disabled\:shadow-md:disabled) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .xl\:flex, + :is(.dark .xl\:dark\:disabled\:flex:disabled) { + display: flex; } } @media (min-width: 1536px) { - .\32 xl\:shadow-md { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + .\32 xl\:flex { + display: flex; } @media (prefers-reduced-motion: no-preference) { - :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:shadow-md:focus-within) { - --tw-shadow: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; - --tw-shadow-colored: 0 4px 6px -1px var(--tw-shadow-color), - 0 2px 4px -2px var(--tw-shadow-color); - box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), - var(--tw-shadow); + :is(.dark .\32 xl\:dark\:motion-safe\:focus-within\:flex:focus-within) { + display: flex; } } } @media (orientation: portrait) { - .portrait\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .portrait\:flex { + display: flex; } } @media (orientation: landscape) { - .landscape\:bg-yellow-300 { - --tw-bg-opacity: 1; - background-color: rgb(253 224 71 / var(--tw-bg-opacity)); + .landscape\:flex { + display: flex; } } diff --git a/tests/variants.test.html b/tests/variants.test.html index bd40b625f..a9b2c2f16 100644 --- a/tests/variants.test.html +++ b/tests/variants.test.html @@ -1,166 +1,166 @@ -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
    -
  • +
-
-
-
-
-
- +
+
+
+
+
+ -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
+
+
+
diff --git a/tests/variants.test.js b/tests/variants.test.js index da62419d4..f948e1b2f 100644 --- a/tests/variants.test.js +++ b/tests/variants.test.js @@ -1,414 +1,83 @@ import fs from 'fs' import path from 'path' import postcss from 'postcss' -import { crosscheck, run, html, css, defaults } from './util/run' +import { run, html, css, defaults } from './util/run' -crosscheck(({ stable, oxide }) => { - test('variants', () => { - let config = { - darkMode: 'class', - content: [path.resolve(__dirname, './variants.test.html')], - corePlugins: { preflight: false }, - } +test('variants', () => { + let config = { + darkMode: 'class', + content: [path.resolve(__dirname, './variants.test.html')], + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` - return run(input, config).then((result) => { - stable - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './variants.test.css'), 'utf8') - ) - oxide - .expect(result.css) - .toMatchFormattedCss( - fs.readFileSync(path.resolve(__dirname, './variants.oxide.test.css'), 'utf8') - ) - }) + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss( + fs.readFileSync(path.resolve(__dirname, './variants.test.css'), 'utf8') + ) }) +}) - test('order matters and produces different behaviour', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - } +test('order matters and produces different behaviour', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + } - return run('@tailwind utilities', config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - .file\:hover\:bg-pink-600:hover::file-selector-button { - --tw-bg-opacity: 1; - background-color: rgb(219 39 119 / var(--tw-bg-opacity)); - } - .hover\:file\:bg-pink-600::file-selector-button:hover { - --tw-bg-opacity: 1; - background-color: rgb(219 39 119 / var(--tw-bg-opacity)); - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - .file\:hover\:bg-pink-600:hover::file-selector-button { - background-color: #db2777; - } - .hover\:file\:bg-pink-600::file-selector-button:hover { - background-color: #db2777; - } - `) - }) - }) - - describe('custom advanced variants', () => { - test('prose-headings usage on its own', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :where(.prose-headings\:text-center) :is(h1, h2, h3, h4) { - text-align: center; - } - `) - }) - }) - - test('prose-headings with another "simple" variant', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - :where(.hover\:prose-headings\:text-center) :is(h1, h2, h3, h4):hover, - :where(.prose-headings\:hover\:text-center:hover) :is(h1, h2, h3, h4) { - text-align: center; - } - `) - }) - }) - - test('prose-headings with another "complex" variant', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') - }, - ], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .group:hover :where(.group-hover\:prose-headings\:text-center) :is(h1, h2, h3, h4), - :where(.group:hover .prose-headings\:group-hover\:text-center) :is(h1, h2, h3, h4) { - text-align: center; - } - `) - }) - }) - - test('using variants with multi-class selectors', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant, addComponents }) { - addComponents({ - '.parent .child': { - foo: 'bar', - }, - }) - addVariant('screen', '@media screen') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media screen { - .screen\:parent .child, - .parent .screen\:child { - foo: bar; - } - } - `) - }) - }) - - test('using multiple classNames in your custom variant', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('my-variant', '&:where(.one, .two, .three)') - }, - ], - } - - let input = css` - @tailwind components; - @tailwind utilities; - - @layer components { - .test { - @apply my-variant:italic; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .test:where(.one, .two, .three) { - font-style: italic; - } - .my-variant\:underline:where(.one, .two, .three) { - text-decoration-line: underline; - } - `) - }) - }) - - test('variant format string must include at-rule or & (1)', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('wtf-bbq', 'lol') - }, - ], - } - - await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( - "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." - ) - }) - - test('variant format string must include at-rule or & (2)', async () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('wtf-bbq', () => 'lol') - }, - ], - } - - await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( - "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." - ) - }) - }) - - test('stacked peer variants', async () => { - let config = { - content: [{ raw: 'peer-disabled:peer-focus:peer-hover:border-blue-500' }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - let result = await run(input, config) - stable.expect(result.css).toIncludeCss(css` - .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:border-blue-500 { - --tw-border-opacity: 1; - border-color: rgb(59 130 246 / var(--tw-border-opacity)); - } - `) - oxide.expect(result.css).toIncludeCss(css` - .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:border-blue-500 { - border-color: #3b82f6; - } - `) - }) - - it('should properly handle keyframes with multiple variants', async () => { - let config = { - content: [ - { - raw: 'animate-spin hover:animate-spin focus:animate-spin hover:animate-bounce focus:animate-bounce', - }, - ], - } - - let input = css` - @tailwind components; - @tailwind utilities; - ` - - let result = await run(input, config) + return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @keyframes spin { - to { - transform: rotate(360deg); - } + .file\:hover\:flex:hover::file-selector-button { + display: flex; } - .animate-spin { - animation: 1s linear infinite spin; - } - @keyframes bounce { - 0%, - 100% { - animation-timing-function: cubic-bezier(0.8, 0, 1, 1); - transform: translateY(-25%); - } - 50% { - animation-timing-function: cubic-bezier(0, 0, 0.2, 1); - transform: none; - } - } - .hover\:animate-bounce:hover { - animation: 1s infinite bounce; - } - .hover\:animate-spin:hover { - animation: 1s linear infinite spin; - } - .focus\:animate-bounce:focus { - animation: 1s infinite bounce; - } - .focus\:animate-spin:focus { - animation: 1s linear infinite spin; + .hover\:file\:flex::file-selector-button:hover { + display: flex; } `) }) +}) - test('custom addVariant with more complex media query params', () => { +describe('custom advanced variants', () => { + test('prose-headings usage on its own', () => { let config = { content: [ { - raw: html`
`, + raw: html`
`, }, ], plugins: [ function ({ addVariant }) { - addVariant('magic', '@media screen and (max-width: 600px)') + addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') }, ], } return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media screen and (max-width: 600px) { - .magic\:text-center { - text-align: center; - } - } - `) - }) - }) - - test('custom addVariant with nested media & format shorthand', () => { - let config = { - content: [ - { - raw: html`
`, - }, - ], - plugins: [ - function ({ addVariant }) { - addVariant('magic', '@supports (hover: hover) { @media print { &:disabled } }') - }, - ], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @supports (hover: hover) { - @media print { - .magic\:text-center:disabled { - text-align: center; - } - } - } - `) - }) - }) - - test('before and after variants are a bit special, and forced to the end', () => { - let config = { - content: [ - { - raw: html` -
-
- `, - }, - ], - plugins: [], - } - - return run('@tailwind components;@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .before\:hover\:text-center:hover:before, - .hover\:before\:text-center:hover:before { - content: var(--tw-content); + :where(.prose-headings\:text-center) :is(h1, h2, h3, h4) { text-align: center; } `) }) }) - test('before and after variants are a bit special, and forced to the end (2)', () => { + test('prose-headings with another "simple" variant', () => { let config = { content: [ { raw: html` -
-
+
+
`, }, ], @@ -421,759 +90,1049 @@ crosscheck(({ stable, oxide }) => { return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - :where(.before\:prose-headings\:text-center) :is(h1, h2, h3, h4):before, - :where(.prose-headings\:before\:text-center) :is(h1, h2, h3, h4):before { - content: var(--tw-content); + :where(.hover\:prose-headings\:text-center) :is(h1, h2, h3, h4):hover, + :where(.prose-headings\:hover\:text-center:hover) :is(h1, h2, h3, h4) { text-align: center; } `) }) }) - test('returning non-strings and non-selectors in addVariant', () => { - /** @type {import('../types/config').Config} */ + test('prose-headings with another "complex" variant', () => { let config = { content: [ { raw: html` -
-
+
+
`, }, ], plugins: [ - function ({ addVariant, e }) { - addVariant('peer-aria-expanded', ({ modifySelectors, separator }) => - // Returning anything other string | string[] | undefined here is not supported - // But we're trying to be lenient here and just throw it out - modifySelectors( - ({ className }) => - `.peer[aria-expanded="true"] ~ .${e(`peer-aria-expanded${separator}${className}`)}` - ) - ) + function ({ addVariant }) { + addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') + }, + ], + } - addVariant('peer-aria-expanded-2', ({ modifySelectors, separator }) => { - let nodes = modifySelectors( - ({ className }) => `.${e(`peer-aria-expanded-2${separator}${className}`)}` - ) + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .group:hover :where(.group-hover\:prose-headings\:text-center) :is(h1, h2, h3, h4), + :where(.group:hover .prose-headings\:group-hover\:text-center) :is(h1, h2, h3, h4) { + text-align: center; + } + `) + }) + }) - return [ - // Returning anything other than strings here is not supported - // But we're trying to be lenient here and just throw it out - nodes, - '.peer[aria-expanded="false"] ~ &', - ] + test('using variants with multi-class selectors', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant, addComponents }) { + addComponents({ + '.parent .child': { + foo: 'bar', + }, }) + addVariant('screen', '@media screen') }, ], } return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - .peer[aria-expanded='true'] ~ .peer-aria-expanded\:text-center, - .peer[aria-expanded='false'] ~ .peer-aria-expanded-2\:text-center { - text-align: center; + @media screen { + .screen\:parent .child, + .parent .screen\:child { + foo: bar; + } } `) }) }) - it('should not generate variants of user css if it is not inside a layer', () => { + test('using multiple classNames in your custom variant', () => { let config = { - content: [{ raw: html`
` }], - plugins: [], + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('my-variant', '&:where(.one, .two, .three)') + }, + ], } let input = css` @tailwind components; @tailwind utilities; - .foo { - color: red; + @layer components { + .test { + @apply my-variant:italic; + } } ` return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - .foo { - color: red; + .test:where(.one, .two, .three) { + font-style: italic; } - `) - }) - }) - - it('should be possible to use responsive modifiers that are defined with special characters', () => { - let config = { - content: [{ raw: html`
` }], - theme: { - screens: { - ' { - return expect(result.css).toMatchFormattedCss(css` - @media (max-width: 399px) { - .\ { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - return run('@tailwind base', config).then((result) => { - return expect(result.css).toMatchFormattedCss( - css` - ${defaults} - ` - ) - }) - }) - - it('variants for components should not be produced in a file without a components layer', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:underline { - text-decoration-line: underline; - } - } - `) - }) - }) - - it('variants for utilities should not be produced in a file without a utilities layer', () => { - let config = { - content: [{ raw: html`
` }], - } - - return run('@tailwind components', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:container { - width: 100%; - } - @media (min-width: 640px) { - .sm\:container { - max-width: 640px; - } - } - @media (min-width: 768px) { - .sm\:container { - max-width: 768px; - } - } - @media (min-width: 1024px) { - .sm\:container { - max-width: 1024px; - } - } - @media (min-width: 1280px) { - .sm\:container { - max-width: 1280px; - } - } - @media (min-width: 1536px) { - .sm\:container { - max-width: 1536px; - } - } - } - `) - }) - }) - - test('The visited variant removes opacity support', () => { - let config = { - content: [ - { - raw: html` - Look, it's a link! - `, - }, - ], - plugins: [], - } - - return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - .visited\:border-red-500:visited { - border-color: #ef4444; - } - .visited\:bg-red-500:visited { - background-color: #ef4444; - } - .visited\:text-red-500:visited { - color: #ef4444; - } - `) - }) - }) - - it('appends variants to the correct place when using postcss documents', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - const doc = postcss.document() - doc.append(postcss.parse(`a {}`)) - doc.append(postcss.parse(`@tailwind base`)) - doc.append(postcss.parse(`@tailwind utilities`)) - doc.append(postcss.parse(`b {}`)) - - const result = doc.toResult() - - return run(result, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - ${defaults} - .underline { + .my-variant\:underline:where(.one, .two, .three) { text-decoration-line: underline; } - @media (min-width: 640px) { - .sm\:underline { - text-decoration-line: underline; - } - } `) }) }) - it('variants support multiple, grouped selectors (html)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .base1 .foo, - .base1 .bar { - color: red; - } - - .base2 .bar .base2-foo { - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:base1 .foo, - .sm\:base1 .bar, - .sm\:base2 .bar .base2-foo { - color: red; - } - } - `) - }) - }) - - it('variants support multiple, grouped selectors (apply)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .base .foo, - .base .bar { - color: red; - } - } - .baz { - @apply sm:base; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .baz .foo, - .baz .bar { - color: red; - } - } - `) - }) - }) - - it('variants only picks the used selectors in a group (html)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .a, - .b { - color: red; - } - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .sm\:b { - color: red; - } - } - `) - }) - }) - - it('variants only picks the used selectors in a group (apply)', () => { - let config = { - content: [{ raw: html`
` }], - plugins: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .a, - .b { - color: red; - } - } - .baz { - @apply sm:b; - } - ` - - return run(input, config).then((result) => { - return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { - .baz { - color: red; - } - } - `) - }) - }) - - test('hoverOnlyWhenSupported adds hover and pointer media features by default', () => { - let config = { - future: { - hoverOnlyWhenSupported: true, - }, - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - @tailwind components; - @tailwind utilities; - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - ${defaults} - @media (hover: hover) and (pointer: fine) { - .hover\:underline:hover, - .group:hover .group-hover\:underline, - .peer:hover ~ .peer-hover\:underline { - text-decoration-line: underline; - } - } - `) - }) - }) - - test('multi-class utilities handle selector-mutating variants correctly', () => { + test('variant format string must include at-rule or & (1)', async () => { let config = { content: [ { - raw: html`
`, - }, - { - raw: html`
`, + raw: html`
`, }, ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - .foo.bar.baz { - color: red; - } - .foo1 .bar1 .baz1 { - color: red; - } - } - ` - - // The second set of ::after cases (w/ descendant selectors) - // are clearly "wrong" BUT you can't have a descendant of a - // pseudo - element so the utilities `after:foo1` and - // `after:bar1` are non-sensical so this is still - // perfectly fine behavior - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .after\:foo.bar.baz:after, - .after\:bar.foo.baz:after, - .after\:baz.foo.bar:after, - .after\:foo1 .bar1 .baz1:after, - .foo1 .after\:bar1 .baz1:after, - .foo1 .bar1 .after\:baz1:after { - content: var(--tw-content); - color: red; - } - .hover\:foo:hover.bar.baz, - .hover\:bar:hover.foo.baz, - .hover\:baz:hover.foo.bar, - .hover\:foo1:hover .bar1 .baz1, - .foo1 .hover\:bar1:hover .baz1, - .foo1 .bar1 .hover\:baz1:hover, - .group:hover .group-hover\:foo.bar.baz, - .group:hover .group-hover\:bar.foo.baz, - .group:hover .group-hover\:baz.foo.bar, - .group:hover .group-hover\:foo1 .bar1 .baz1, - .foo1 .group:hover .group-hover\:bar1 .baz1, - .foo1 .bar1 .group:hover .group-hover\:baz1, - .peer:checked ~ .peer-checked\:foo.bar.baz, - .peer:checked ~ .peer-checked\:bar.foo.baz, - .peer:checked ~ .peer-checked\:baz.foo.bar, - .peer:checked ~ .peer-checked\:foo1 .bar1 .baz1, - .foo1 .peer:checked ~ .peer-checked\:bar1 .baz1, - .foo1 .bar1 .peer:checked ~ .peer-checked\:baz1 { - color: red; - } - `) - }) - }) - - test('class inside pseudo-class function :has', () => { - let config = { - content: [ - { raw: html`
` }, - { raw: html`
` }, - { raw: html`
` }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - @layer utilities { - :where(.foo) { - color: red; - } - :is(.foo, .bar, .baz) { - color: orange; - } - :is(.foo) { - color: yellow; - } - html:has(.foo) { - color: green; - } - } - ` - - return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - :where(.foo) { - color: red; - } - :is(.foo, .bar, .baz) { - color: orange; - } - .foo { - color: #ff0; - } - html:has(.foo) { - color: green; - } - :where(.hover\:foo:hover) { - color: red; - } - :is(.hover\:foo:hover, .bar, .baz), - :is(.foo, .hover\:bar:hover, .baz), - :is(.foo, .bar, .hover\:baz:hover) { - color: orange; - } - .hover\:foo:hover { - color: #ff0; - } - html:has(.hover\:foo:hover) { - color: green; - } - @media (min-width: 640px) { - :where(.sm\:foo) { - color: red; - } - :is(.sm\:foo, .bar, .baz), - :is(.foo, .sm\:bar, .baz), - :is(.foo, .bar, .sm\:baz) { - color: orange; - } - .sm\:foo { - color: #ff0; - } - html:has(.sm\:foo) { - color: green; - } - } - `) - }) - }) - - test('variant functions returning arrays should output correct results when nesting', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, plugins: [ - function ({ addUtilities, addVariant }) { - addVariant('test', () => ['@media (test)']) - addUtilities({ - '.foo': { - display: 'grid', - '> *': { - 'grid-column': 'span 2', - }, - }, - }) + function ({ addVariant }) { + addVariant('wtf-bbq', 'lol') }, ], } - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - @media (test) { - .test\:foo { - display: grid; - } - .test\:foo > * { - grid-column: span 2; - } - } - `) + await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( + "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." + ) }) - test('variants with slashes in them work', () => { + test('variant format string must include at-rule or & (2)', async () => { let config = { content: [ { - raw: html`
ar-1/10
`, + raw: html`
`, }, ], - theme: { - extend: { - screens: { - 'ar-1/10': { raw: '(min-aspect-ratio: 1/10)' }, - }, - }, - }, - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) { - .ar-1\/10\:text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - } - } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) { - .ar-1\/10\:text-red-500 { - color: #ef4444; - } - } - `) - }) - }) - - test('variants with slashes support modifiers', () => { - let config = { - content: [ - { - raw: html`
ar-1/10
`, - }, - ], - corePlugins: { preflight: false }, plugins: [ - function ({ matchVariant }) { - matchVariant( - 'ar', - (value, { modifier }) => { - return [`@media (min-aspect-ratio: ${value}) and (foo: ${modifier})`] - }, - { values: { '1/10': '1/10' } } - ) + function ({ addVariant }) { + addVariant('wtf-bbq', () => 'lol') }, ], } - let input = css` - @tailwind utilities; - ` + await expect(run('@tailwind components;@tailwind utilities', config)).rejects.toThrowError( + "Your custom variant `wtf-bbq` has an invalid format string. Make sure it's an at-rule or contains a `&` placeholder." + ) + }) +}) - return run(input, config).then((result) => { - stable.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) and (foo: 20) { - .ar-1\/10\/20\:text-red-500 { - --tw-text-opacity: 1; - color: rgb(239 68 68 / var(--tw-text-opacity)); - } +test('stacked peer variants', async () => { + let config = { + content: [{ raw: 'peer-disabled:peer-focus:peer-hover:flex' }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + let result = await run(input, config) + expect(result.css).toIncludeCss(css` + .peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:flex { + display: flex; + } + `) +}) + +it('should properly handle keyframes with multiple variants', async () => { + let config = { + content: [ + { + raw: 'animate-spin hover:animate-spin focus:animate-spin hover:animate-bounce focus:animate-bounce', + }, + ], + } + + let input = css` + @tailwind components; + @tailwind utilities; + ` + + let result = await run(input, config) + expect(result.css).toMatchFormattedCss(css` + @keyframes spin { + to { + transform: rotate(360deg); + } + } + .animate-spin { + animation: 1s linear infinite spin; + } + @keyframes bounce { + 0%, + 100% { + animation-timing-function: cubic-bezier(0.8, 0, 1, 1); + transform: translateY(-25%); + } + 50% { + animation-timing-function: cubic-bezier(0, 0, 0.2, 1); + transform: none; + } + } + .hover\:animate-bounce:hover { + animation: 1s infinite bounce; + } + .hover\:animate-spin:hover { + animation: 1s linear infinite spin; + } + .focus\:animate-bounce:focus { + animation: 1s infinite bounce; + } + .focus\:animate-spin:focus { + animation: 1s linear infinite spin; + } + `) +}) + +test('custom addVariant with more complex media query params', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('magic', '@media screen and (max-width: 600px)') + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media screen and (max-width: 600px) { + .magic\:text-center { + text-align: center; } - `) - oxide.expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) and (foo: 20) { - .ar-1\/10\/20\:text-red-500 { - color: #ef4444; - } - } - `) - }) - }) - - test('arbitrary variant selectors should not re-order scrollbar pseudo classes', async () => { - let config = { - content: [ - { - raw: html` -
-
-
-
-
-
-
- `, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - .\[\&\:\:-webkit-resizer\:hover\]\:underline::-webkit-resizer:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-button\:hover\]\:underline::-webkit-scrollbar-button:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-corner\:hover\]\:underline::-webkit-scrollbar-corner:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-thumb\:hover\]\:underline::-webkit-scrollbar-thumb:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-track-piece\:hover\]\:underline::-webkit-scrollbar-track-piece:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar-track\:hover\]\:underline::-webkit-scrollbar-track:hover { - text-decoration-line: underline; - } - .\[\&\:\:-webkit-scrollbar\:hover\]\:underline::-webkit-scrollbar:hover { - text-decoration-line: underline; - } - `) - }) - - test('stacking dark and rtl variants', async () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - :is(.dark :is([dir='rtl'] .dark\:rtl\:italic)) { - font-style: italic; - } - `) - }) - - test('stacking dark and rtl variants with pseudo elements', async () => { - let config = { - darkMode: 'class', - content: [ - { - raw: html`
`, - }, - ], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - let result = await run(input, config) - - expect(result.css).toMatchFormattedCss(css` - :is(.dark :is([dir='rtl'] .dark\:rtl\:placeholder\:italic))::placeholder { - font-style: italic; } `) }) }) + +test('custom addVariant with nested media & format shorthand', () => { + let config = { + content: [ + { + raw: html`
`, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('magic', '@supports (hover: hover) { @media print { &:disabled } }') + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @supports (hover: hover) { + @media print { + .magic\:text-center:disabled { + text-align: center; + } + } + } + `) + }) +}) + +test('before and after variants are a bit special, and forced to the end', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + plugins: [], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .before\:hover\:text-center:hover:before, + .hover\:before\:text-center:hover:before { + content: var(--tw-content); + text-align: center; + } + `) + }) +}) + +test('before and after variants are a bit special, and forced to the end (2)', () => { + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + plugins: [ + function ({ addVariant }) { + addVariant('prose-headings', ':where(&) :is(h1, h2, h3, h4)') + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + :where(.before\:prose-headings\:text-center) :is(h1, h2, h3, h4):before, + :where(.prose-headings\:before\:text-center) :is(h1, h2, h3, h4):before { + content: var(--tw-content); + text-align: center; + } + `) + }) +}) + +test('returning non-strings and non-selectors in addVariant', () => { + /** @type {import('../types/config').Config} */ + let config = { + content: [ + { + raw: html` +
+
+ `, + }, + ], + plugins: [ + function ({ addVariant, e }) { + addVariant('peer-aria-expanded', ({ modifySelectors, separator }) => + // Returning anything other string | string[] | undefined here is not supported + // But we're trying to be lenient here and just throw it out + modifySelectors( + ({ className }) => + `.peer[aria-expanded="true"] ~ .${e(`peer-aria-expanded${separator}${className}`)}` + ) + ) + + addVariant('peer-aria-expanded-2', ({ modifySelectors, separator }) => { + let nodes = modifySelectors( + ({ className }) => `.${e(`peer-aria-expanded-2${separator}${className}`)}` + ) + + return [ + // Returning anything other than strings here is not supported + // But we're trying to be lenient here and just throw it out + nodes, + '.peer[aria-expanded="false"] ~ &', + ] + }) + }, + ], + } + + return run('@tailwind components;@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .peer[aria-expanded='true'] ~ .peer-aria-expanded\:text-center, + .peer[aria-expanded='false'] ~ .peer-aria-expanded-2\:text-center { + text-align: center; + } + `) + }) +}) + +it('should not generate variants of user css if it is not inside a layer', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + } + + let input = css` + @tailwind components; + @tailwind utilities; + + .foo { + color: red; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .foo { + color: red; + } + `) + }) +}) + +it('should be possible to use responsive modifiers that are defined with special characters', () => { + let config = { + content: [{ raw: html`
` }], + theme: { + screens: { + ' { + return expect(result.css).toMatchFormattedCss(css` + @media (max-width: 399px) { + .\ { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + return run('@tailwind base', config).then((result) => { + return expect(result.css).toMatchFormattedCss( + css` + ${defaults} + ` + ) + }) +}) + +it('variants for components should not be produced in a file without a components layer', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:underline { + text-decoration-line: underline; + } + } + `) + }) +}) + +it('variants for utilities should not be produced in a file without a utilities layer', () => { + let config = { + content: [{ raw: html`
` }], + } + + return run('@tailwind components', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:container { + width: 100%; + } + @media (min-width: 640px) { + .sm\:container { + max-width: 640px; + } + } + @media (min-width: 768px) { + .sm\:container { + max-width: 768px; + } + } + @media (min-width: 1024px) { + .sm\:container { + max-width: 1024px; + } + } + @media (min-width: 1280px) { + .sm\:container { + max-width: 1280px; + } + } + @media (min-width: 1536px) { + .sm\:container { + max-width: 1536px; + } + } + } + `) + }) +}) + +test('The visited variant removes opacity support', () => { + let config = { + content: [ + { + raw: html` + Look, it's a link! + `, + }, + ], + plugins: [], + } + + return run('@tailwind utilities', config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + .visited\:border-red-500:visited { + border-color: #ef4444; + } + .visited\:bg-red-500:visited { + background-color: #ef4444; + } + .visited\:text-red-500:visited { + color: #ef4444; + } + `) + }) +}) + +it('appends variants to the correct place when using postcss documents', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + const doc = postcss.document() + doc.append(postcss.parse(`a {}`)) + doc.append(postcss.parse(`@tailwind base`)) + doc.append(postcss.parse(`@tailwind utilities`)) + doc.append(postcss.parse(`b {}`)) + + const result = doc.toResult() + + return run(result, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + ${defaults} + .underline { + text-decoration-line: underline; + } + @media (min-width: 640px) { + .sm\:underline { + text-decoration-line: underline; + } + } + `) + }) +}) + +it('variants support multiple, grouped selectors (html)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .base1 .foo, + .base1 .bar { + color: red; + } + + .base2 .bar .base2-foo { + color: red; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:base1 .foo, + .sm\:base1 .bar, + .sm\:base2 .bar .base2-foo { + color: red; + } + } + `) + }) +}) + +it('variants support multiple, grouped selectors (apply)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .base .foo, + .base .bar { + color: red; + } + } + .baz { + @apply sm:base; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .baz .foo, + .baz .bar { + color: red; + } + } + `) + }) +}) + +it('variants only picks the used selectors in a group (html)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .a, + .b { + color: red; + } + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .sm\:b { + color: red; + } + } + `) + }) +}) + +it('variants only picks the used selectors in a group (apply)', () => { + let config = { + content: [{ raw: html`
` }], + plugins: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .a, + .b { + color: red; + } + } + .baz { + @apply sm:b; + } + ` + + return run(input, config).then((result) => { + return expect(result.css).toMatchFormattedCss(css` + @media (min-width: 640px) { + .baz { + color: red; + } + } + `) + }) +}) + +test('hoverOnlyWhenSupported adds hover and pointer media features by default', () => { + let config = { + future: { + hoverOnlyWhenSupported: true, + }, + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + @media (hover: hover) and (pointer: fine) { + .hover\:underline:hover, + .group:hover .group-hover\:underline, + .peer:hover ~ .peer-hover\:underline { + text-decoration-line: underline; + } + } + `) + }) +}) + +test('multi-class utilities handle selector-mutating variants correctly', () => { + let config = { + content: [ + { + raw: html`
`, + }, + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + .foo.bar.baz { + color: red; + } + .foo1 .bar1 .baz1 { + color: red; + } + } + ` + + // The second set of ::after cases (w/ descendant selectors) + // are clearly "wrong" BUT you can't have a descendant of a + // pseudo - element so the utilities `after:foo1` and + // `after:bar1` are non-sensical so this is still + // perfectly fine behavior + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .after\:foo.bar.baz:after, + .after\:bar.foo.baz:after, + .after\:baz.foo.bar:after, + .after\:foo1 .bar1 .baz1:after, + .foo1 .after\:bar1 .baz1:after, + .foo1 .bar1 .after\:baz1:after { + content: var(--tw-content); + color: red; + } + .hover\:foo:hover.bar.baz, + .hover\:bar:hover.foo.baz, + .hover\:baz:hover.foo.bar, + .hover\:foo1:hover .bar1 .baz1, + .foo1 .hover\:bar1:hover .baz1, + .foo1 .bar1 .hover\:baz1:hover, + .group:hover .group-hover\:foo.bar.baz, + .group:hover .group-hover\:bar.foo.baz, + .group:hover .group-hover\:baz.foo.bar, + .group:hover .group-hover\:foo1 .bar1 .baz1, + .foo1 .group:hover .group-hover\:bar1 .baz1, + .foo1 .bar1 .group:hover .group-hover\:baz1, + .peer:checked ~ .peer-checked\:foo.bar.baz, + .peer:checked ~ .peer-checked\:bar.foo.baz, + .peer:checked ~ .peer-checked\:baz.foo.bar, + .peer:checked ~ .peer-checked\:foo1 .bar1 .baz1, + .foo1 .peer:checked ~ .peer-checked\:bar1 .baz1, + .foo1 .bar1 .peer:checked ~ .peer-checked\:baz1 { + color: red; + } + `) + }) +}) + +test('class inside pseudo-class function :has', () => { + let config = { + content: [ + { raw: html`
` }, + { raw: html`
` }, + { raw: html`
` }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + @layer utilities { + :where(.foo) { + color: red; + } + :is(.foo, .bar, .baz) { + color: orange; + } + :is(.foo) { + color: yellow; + } + html:has(.foo) { + color: green; + } + } + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + :where(.foo) { + color: red; + } + :is(.foo, .bar, .baz) { + color: orange; + } + .foo { + color: #ff0; + } + html:has(.foo) { + color: green; + } + :where(.hover\:foo:hover) { + color: red; + } + :is(.hover\:foo:hover, .bar, .baz), + :is(.foo, .hover\:bar:hover, .baz), + :is(.foo, .bar, .hover\:baz:hover) { + color: orange; + } + .hover\:foo:hover { + color: #ff0; + } + html:has(.hover\:foo:hover) { + color: green; + } + @media (min-width: 640px) { + :where(.sm\:foo) { + color: red; + } + :is(.sm\:foo, .bar, .baz), + :is(.foo, .sm\:bar, .baz), + :is(.foo, .bar, .sm\:baz) { + color: orange; + } + .sm\:foo { + color: #ff0; + } + html:has(.sm\:foo) { + color: green; + } + } + `) + }) +}) + +test('variant functions returning arrays should output correct results when nesting', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + plugins: [ + function ({ addUtilities, addVariant }) { + addVariant('test', () => ['@media (test)']) + addUtilities({ + '.foo': { + display: 'grid', + '> *': { + 'grid-column': 'span 2', + }, + }, + }) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + @media (test) { + .test\:foo { + display: grid; + } + .test\:foo > * { + grid-column: span 2; + } + } + `) +}) + +test('variants with slashes in them work', () => { + let config = { + content: [ + { + raw: html`
ar-1/10
`, + }, + ], + theme: { + extend: { + screens: { + 'ar-1/10': { raw: '(min-aspect-ratio: 1/10)' }, + }, + }, + }, + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-aspect-ratio: 1 / 10) { + .ar-1\/10\:flex { + display: flex; + } + } + `) + }) +}) + +test('variants with slashes support modifiers', () => { + let config = { + content: [ + { + raw: html`
ar-1/10
`, + }, + ], + corePlugins: { preflight: false }, + plugins: [ + function ({ matchVariant }) { + matchVariant( + 'ar', + (value, { modifier }) => { + return [`@media (min-aspect-ratio: ${value}) and (foo: ${modifier})`] + }, + { values: { '1/10': '1/10' } } + ) + }, + ], + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + @media (min-aspect-ratio: 1 / 10) and (foo: 20) { + .ar-1\/10\/20\:flex { + display: flex; + } + } + `) + }) +}) + +test('arbitrary variant selectors should not re-order scrollbar pseudo classes', async () => { + let config = { + content: [ + { + raw: html` +
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + .\[\&\:\:-webkit-resizer\:hover\]\:underline::-webkit-resizer:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-button\:hover\]\:underline::-webkit-scrollbar-button:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-corner\:hover\]\:underline::-webkit-scrollbar-corner:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-thumb\:hover\]\:underline::-webkit-scrollbar-thumb:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-track-piece\:hover\]\:underline::-webkit-scrollbar-track-piece:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar-track\:hover\]\:underline::-webkit-scrollbar-track:hover { + text-decoration-line: underline; + } + .\[\&\:\:-webkit-scrollbar\:hover\]\:underline::-webkit-scrollbar:hover { + text-decoration-line: underline; + } + `) +}) + +test('stacking dark and rtl variants', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + :is(.dark :is([dir='rtl'] .dark\:rtl\:italic)) { + font-style: italic; + } + `) +}) + +test('stacking dark and rtl variants with pseudo elements', async () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html`
`, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config) + + expect(result.css).toMatchFormattedCss(css` + :is(.dark :is([dir='rtl'] .dark\:rtl\:placeholder\:italic))::placeholder { + font-style: italic; + } + `) +}) diff --git a/tests/warnings.test.js b/tests/warnings.test.js index d2be7189f..d74f1dd52 100644 --- a/tests/warnings.test.js +++ b/tests/warnings.test.js @@ -1,64 +1,61 @@ -import { crosscheck, run, html, css } from './util/run' +import { run, html, css } from './util/run' -crosscheck(({ oxide, stable }) => { - // The oxide engine will use auto content if no `content` is given - oxide.test.todo('it warns when there is no content key') - stable.test('it warns when there is no content key', async () => { - let config = { - corePlugins: { preflight: false }, - } +test('it warns when there is no content key', async () => { + let config = { + presets: [], // Prevents the default config from being merged in and therefore `content: ['auto']` is not used. + corePlugins: { preflight: false }, + } - let input = css` - @tailwind base; - ` + let input = css` + @tailwind base; + ` - await run(input, config) + await run(input, config) - expect().toHaveBeenWarnedWith(['content-problems']) - }) - - test('it warns when there is an empty content key', async () => { - let config = { - content: [], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind base; - ` - - await run(input, config) - - expect().toHaveBeenWarnedWith(['content-problems']) - }) - - test('it warns when there are no utilities generated', async () => { - let config = { - content: [{ raw: html`nothing here matching a utility` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - expect().toHaveBeenWarnedWith(['content-problems']) - }) - - it('warnings are not thrown when only variant utilities are generated', async () => { - let config = { - content: [{ raw: html`
` }], - corePlugins: { preflight: false }, - } - - let input = css` - @tailwind utilities; - ` - - await run(input, config) - - expect().not.toHaveBeenWarned() - }) + expect().toHaveBeenWarnedWith(['content-problems']) +}) + +test('it warns when there is an empty content key', async () => { + let config = { + content: [], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind base; + ` + + await run(input, config) + + expect().toHaveBeenWarnedWith(['content-problems']) +}) + +test('it warns when there are no utilities generated', async () => { + let config = { + content: [{ raw: html`nothing here matching a utility` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + expect().toHaveBeenWarnedWith(['content-problems']) +}) + +it('warnings are not thrown when only variant utilities are generated', async () => { + let config = { + content: [{ raw: html`
` }], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + await run(input, config) + + expect().not.toHaveBeenWarned() }) diff --git a/tests/withAlphaVariable.test.js b/tests/withAlphaVariable.test.js index 29d39c7aa..d543dfc6e 100644 --- a/tests/withAlphaVariable.test.js +++ b/tests/withAlphaVariable.test.js @@ -1,243 +1,240 @@ import withAlphaVariable from '../src/util/withAlphaVariable' -import { crosscheck } from './util/run' -crosscheck(() => { - test('it adds the right custom property', () => { - expect( - withAlphaVariable({ color: '#ff0000', property: 'color', variable: '--tw-text-opacity' }) - ).toEqual({ - '--tw-text-opacity': '1', - color: 'rgb(255 0 0 / var(--tw-text-opacity))', - }) - expect( - withAlphaVariable({ - color: 'hsl(240 100% 50%)', - property: 'color', - variable: '--tw-text-opacity', - }) - ).toEqual({ - '--tw-text-opacity': '1', - color: 'hsl(240 100% 50% / var(--tw-text-opacity))', - }) +test('it adds the right custom property', () => { + expect( + withAlphaVariable({ color: '#ff0000', property: 'color', variable: '--tw-text-opacity' }) + ).toEqual({ + '--tw-text-opacity': '1', + color: 'rgb(255 0 0 / var(--tw-text-opacity))', }) - - test('it ignores colors that cannot be parsed', () => { - expect( - withAlphaVariable({ - color: 'currentColor', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'currentColor', - }) - expect( - withAlphaVariable({ - color: 'rgb(255, 0)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(255, 0)', - }) - expect( - withAlphaVariable({ - color: 'rgb(255)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(255)', - }) - expect( - withAlphaVariable({ - color: 'rgb(255, 0, 0, 255)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(255, 0, 0, 255)', - }) - expect( - withAlphaVariable({ - color: 'rgb(var(--color))', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgb(var(--color))', - }) - }) - - test('it ignores colors that already have an alpha channel', () => { - expect( - withAlphaVariable({ - color: '#ff0000ff', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#ff0000ff', - }) - expect( - withAlphaVariable({ - color: '#ff000080', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#ff000080', - }) - expect( - withAlphaVariable({ - color: '#f00a', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#f00a', - }) - expect( - withAlphaVariable({ - color: '#f00f', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': '#f00f', - }) - expect( - withAlphaVariable({ - color: 'rgba(255, 255, 255, 1)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgba(255, 255, 255, 1)', - }) - expect( - withAlphaVariable({ - color: 'rgba(255, 255, 255, 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgba(255, 255, 255, 0.5)', - }) - expect( - withAlphaVariable({ - color: 'rgba(255 255 255 / 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'rgba(255 255 255 / 0.5)', - }) - expect( - withAlphaVariable({ - color: 'hsla(240, 100%, 50%, 1)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'hsla(240, 100%, 50%, 1)', - }) - expect( - withAlphaVariable({ - color: 'hsla(240, 100%, 50%, 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'hsla(240, 100%, 50%, 0.5)', - }) - expect( - withAlphaVariable({ - color: 'hsl(240 100% 50% / 0.5)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - 'background-color': 'hsl(240 100% 50% / 0.5)', - }) - }) - - test('it allows a closure to be passed', () => { - expect( - withAlphaVariable({ - color: ({ opacityVariable }) => `rgba(0, 0, 0, var(${opacityVariable}))`, - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: ({ opacityValue }) => `rgba(0, 0, 0, ${opacityValue})`, - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', - }) - }) - - test('it transforms rgb and hsl to space-separated rgb and hsl', () => { - expect( - withAlphaVariable({ - color: 'rgb(50, 50, 50)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: 'rgb(50 50 50)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: 'hsl(50, 50%, 50%)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', - }) - expect( - withAlphaVariable({ - color: 'hsl(50 50% 50%)', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', - }) - }) - - test('it transforms named colors to rgb', () => { - expect( - withAlphaVariable({ - color: 'red', - property: 'background-color', - variable: '--tw-bg-opacity', - }) - ).toEqual({ - '--tw-bg-opacity': '1', - 'background-color': 'rgb(255 0 0 / var(--tw-bg-opacity))', + expect( + withAlphaVariable({ + color: 'hsl(240 100% 50%)', + property: 'color', + variable: '--tw-text-opacity', }) + ).toEqual({ + '--tw-text-opacity': '1', + color: 'hsl(240 100% 50% / var(--tw-text-opacity))', + }) +}) + +test('it ignores colors that cannot be parsed', () => { + expect( + withAlphaVariable({ + color: 'currentColor', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'currentColor', + }) + expect( + withAlphaVariable({ + color: 'rgb(255, 0)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(255, 0)', + }) + expect( + withAlphaVariable({ + color: 'rgb(255)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(255)', + }) + expect( + withAlphaVariable({ + color: 'rgb(255, 0, 0, 255)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(255, 0, 0, 255)', + }) + expect( + withAlphaVariable({ + color: 'rgb(var(--color))', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgb(var(--color))', + }) +}) + +test('it ignores colors that already have an alpha channel', () => { + expect( + withAlphaVariable({ + color: '#ff0000ff', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#ff0000ff', + }) + expect( + withAlphaVariable({ + color: '#ff000080', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#ff000080', + }) + expect( + withAlphaVariable({ + color: '#f00a', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#f00a', + }) + expect( + withAlphaVariable({ + color: '#f00f', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': '#f00f', + }) + expect( + withAlphaVariable({ + color: 'rgba(255, 255, 255, 1)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgba(255, 255, 255, 1)', + }) + expect( + withAlphaVariable({ + color: 'rgba(255, 255, 255, 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgba(255, 255, 255, 0.5)', + }) + expect( + withAlphaVariable({ + color: 'rgba(255 255 255 / 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'rgba(255 255 255 / 0.5)', + }) + expect( + withAlphaVariable({ + color: 'hsla(240, 100%, 50%, 1)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'hsla(240, 100%, 50%, 1)', + }) + expect( + withAlphaVariable({ + color: 'hsla(240, 100%, 50%, 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'hsla(240, 100%, 50%, 0.5)', + }) + expect( + withAlphaVariable({ + color: 'hsl(240 100% 50% / 0.5)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + 'background-color': 'hsl(240 100% 50% / 0.5)', + }) +}) + +test('it allows a closure to be passed', () => { + expect( + withAlphaVariable({ + color: ({ opacityVariable }) => `rgba(0, 0, 0, var(${opacityVariable}))`, + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: ({ opacityValue }) => `rgba(0, 0, 0, ${opacityValue})`, + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgba(0, 0, 0, var(--tw-bg-opacity))', + }) +}) + +test('it transforms rgb and hsl to space-separated rgb and hsl', () => { + expect( + withAlphaVariable({ + color: 'rgb(50, 50, 50)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: 'rgb(50 50 50)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgb(50 50 50 / var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: 'hsl(50, 50%, 50%)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', + }) + expect( + withAlphaVariable({ + color: 'hsl(50 50% 50%)', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'hsl(50 50% 50% / var(--tw-bg-opacity))', + }) +}) + +test('it transforms named colors to rgb', () => { + expect( + withAlphaVariable({ + color: 'red', + property: 'background-color', + variable: '--tw-bg-opacity', + }) + ).toEqual({ + '--tw-bg-opacity': '1', + 'background-color': 'rgb(255 0 0 / var(--tw-bg-opacity))', }) }) diff --git a/turbo.json b/turbo.json index ef1c9043d..8ddd398f5 100644 --- a/turbo.json +++ b/turbo.json @@ -2,7 +2,7 @@ "$schema": "https://turbo.build/schema.json", "pipeline": { "//#build": { - "outputs": ["lib/**", "peers/**", "types/generated/**"], + "outputs": ["lib/**", "types/generated/**"], "inputs": ["src/**", "oxide/**", "nesting/**", "oxide-node-api-shim/**", "types/**"] }, "test": { From 49400f90f1a7983ba560e024c589b2950db18d88 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 25 May 2023 12:01:03 +0200 Subject: [PATCH 29/85] fix CI badge in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 17663787f..625b83ad5 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@

- Build Status + Build Status Total Downloads Latest Release License From 88ab01c7f846f40aa65a9f1b9e57f0eead953897 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 25 May 2023 12:14:36 +0200 Subject: [PATCH 30/85] update `build-linux` steps in release workflows --- .github/workflows/release-insiders.yml | 12 +++++------- .github/workflows/release.yml | 12 +++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release-insiders.yml b/.github/workflows/release-insiders.yml index 26e1b1167..d6eb24606 100644 --- a/.github/workflows/release-insiders.yml +++ b/.github/workflows/release-insiders.yml @@ -170,15 +170,13 @@ jobs: include: - target: x86_64-unknown-linux-gnu strip: strip - image: docker.io/centos/nodejs-12-centos7 + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - target: aarch64-unknown-linux-gnu - strip: aarch64-linux-gnu-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 - target: armv7-unknown-linux-gnueabihf - strip: arm-linux-gnueabihf-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig - target: aarch64-unknown-linux-musl image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine strip: aarch64-linux-musl-strip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3a1ab964d..5c9da43c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -172,15 +172,13 @@ jobs: include: - target: x86_64-unknown-linux-gnu strip: strip - image: docker.io/centos/nodejs-14-centos7 + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - target: aarch64-unknown-linux-gnu - strip: aarch64-linux-gnu-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 - target: armv7-unknown-linux-gnueabihf - strip: arm-linux-gnueabihf-strip - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - setup: apt install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y + strip: llvm-strip + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig - target: aarch64-unknown-linux-musl image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine strip: aarch64-linux-musl-strip From 04c4de1997212d1cfd1045be4c32ff75dae19ec5 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 25 May 2023 16:06:00 +0200 Subject: [PATCH 31/85] Deprecate `--no-autoprefixer` flag in the CLI (#11280) * enable `--no-autoprefixer` test * handle `--no-autoprefixer` using lightningcss * bump default chrome version for lightningcss plugin * handle `map` being nullable * add `--no-autoprefixer` test including nesting * set Chrome to version 111 as a default value * resolve the output message when resolving the promise * deprecate `--no-autoprefixer` for the CLI * update changelog --- CHANGELOG.md | 1 + integrations/execute.js | 2 +- .../tailwindcss-cli/tests/cli.test.js | 39 +++++++++++-------- src/cli/build/index.js | 4 ++ src/cli/build/plugin.js | 16 +++++--- src/cli/index.js | 1 + src/plugin.js | 2 +- 7 files changed, 41 insertions(+), 24 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36ce4de0e..8585cad4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reset padding for `

` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) - [Oxide] Disable color opacity plugins by default in the `oxide` engine ([#10618](https://github.com/tailwindlabs/tailwindcss/pull/10618)) - [Oxide] Enable relative content paths for the `oxide` engine ([#10621](https://github.com/tailwindlabs/tailwindcss/pull/10621)) +- Deprecate `--no-autoprefixer` flag in the CLI ([#11280](https://github.com/tailwindlabs/tailwindcss/pull/11280)) ## [3.3.2] - 2023-04-25 diff --git a/integrations/execute.js b/integrations/execute.js index 6c5f20363..f6dda33a6 100644 --- a/integrations/execute.js +++ b/integrations/execute.js @@ -64,7 +64,7 @@ module.exports = function $(command, options = {}) { messages.splice(0, idx + 1) let actorIdx = actors.indexOf(next) actors.splice(actorIdx, 1) - next.resolve() + next.resolve(message) break } } diff --git a/integrations/tailwindcss-cli/tests/cli.test.js b/integrations/tailwindcss-cli/tests/cli.test.js index cf15425bb..0ae5e056f 100644 --- a/integrations/tailwindcss-cli/tests/cli.test.js +++ b/integrations/tailwindcss-cli/tests/cli.test.js @@ -96,27 +96,35 @@ describe('Build command', () => { expect(withoutMinify.length).toBeGreaterThan(withMinify.length) }) - // TODO: Handle --no-autoprefixer - test.skip('--no-autoprefixer', async () => { + // Deprecated + test('--no-autoprefixer (should produce a warning)', async () => { await writeInputFile('index.html', html`
`) + await writeInputFile( + 'index.css', + css` + @tailwind utilities; + ` + ) - await $(`${EXECUTABLE} --output ./dist/main.css`) - let withAutoprefixer = await readOutputFile('main.css') + let runningProcess = $( + `${EXECUTABLE} --input ./src/index.css --output ./dist/main.css --no-autoprefixer` + ) + let warning = runningProcess.onStderr((message) => message.includes('--no-autoprefixer')) + await runningProcess + expect(await warning).toMatchInlineSnapshot(` + "[deprecation] The --no-autoprefixer flag is deprecated and has no effect. + " + `) + let withoutAutoprefixer = await readOutputFile('main.css') - expect(withAutoprefixer).toIncludeCss(css` - .select-none { + // This contains --webkit-user-select which may be strange, but it is expected because we are + // not handling the `--no-autoprefixer` flag anymore at all. + expect(withoutAutoprefixer).toMatchInlineSnapshot(` + ".select-none { -webkit-user-select: none; user-select: none; } - `) - - await $(`${EXECUTABLE} --output ./dist/main.css --no-autoprefixer`) - let withoutAutoprefixer = await readOutputFile('main.css') - - expect(withoutAutoprefixer).toIncludeCss(css` - .select-none { - user-select: none; - } + " `) }) @@ -492,7 +500,6 @@ describe('Build command', () => { --postcss Load custom PostCSS configuration -m, --minify Minify the output -c, --config Path to a custom config file - --no-autoprefixer Disable autoprefixer -h, --help Display usage information `) ) diff --git a/src/cli/build/index.js b/src/cli/build/index.js index 62c020e59..a142a4a47 100644 --- a/src/cli/build/index.js +++ b/src/cli/build/index.js @@ -25,6 +25,10 @@ export async function build(args) { process.exit(9) } + if (args['--no-autoprefixer']) { + console.error('[deprecation] The --no-autoprefixer flag is deprecated and has no effect.') + } + // TODO: Reference the @config path here if exists let configPath = args['--config'] ? args['--config'] : resolveDefaultConfigPath() diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index ee30eb442..e83311937 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -26,14 +26,13 @@ import { validateConfig } from '../../util/validateConfig' import { handleImportAtRules } from '../../lib/handleImportAtRules' import { flagEnabled } from '../../featureFlags' -async function lightningcss(shouldMinify, result, options = {}) { - // TODO: handle --no-autoprefixer option if possible +async function lightningcss(result, { map = true, minify = true } = {}) { try { let transformed = lightning.transform({ filename: result.opts.from || 'input.css', code: Buffer.from(result.css, 'utf-8'), - minify: shouldMinify, - sourceMap: result.map === undefined ? options.map : !!result.map, + minify, + sourceMap: result.map === undefined ? map : !!result.map, inputSourceMap: result.map ? result.map.toString() : undefined, targets: lightning.browserslistToTargets(browserslist(pkg.browserslist)), drafts: { @@ -46,7 +45,7 @@ async function lightningcss(shouldMinify, result, options = {}) { map: result.map ? Object.assign(result.map, { toString() { - return transformed.map.toString() + return transformed.map?.toString() }, }) : result.map, @@ -342,7 +341,12 @@ export async function createProcessor(args, cliConfigPath) { return readInput() .then((css) => processor.process(css, options)) - .then((result) => lightningcss(!!args['--minify'], result, options)) + .then((result) => + lightningcss(result, { + ...options, + minify: !!args['--minify'], + }) + ) .then((result) => { if (!state.watcher) { return result diff --git a/src/cli/index.js b/src/cli/index.js index fc1497f62..66dda931c 100644 --- a/src/cli/index.js +++ b/src/cli/index.js @@ -70,6 +70,7 @@ let commands = { description: 'Path to a custom config file', }, '--no-autoprefixer': { + deprecated: true, type: Boolean, description: 'Disable autoprefixer', }, diff --git a/src/plugin.js b/src/plugin.js index bfcdc6583..4356add62 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -49,7 +49,7 @@ module.exports = function tailwindcss(configOrPath) { inputSourceMap: result.map ? result.map.toString() : undefined, targets: typeof process !== 'undefined' && process.env.JEST_WORKER_ID - ? { chrome: 106 << 16 } + ? { chrome: 111 << 16 } : lightningcss.browserslistToTargets( browserslist(require('../package.json').browserslist) ), From 0917fcaa338d13dff7ca66b8dbeacb1df8df75a0 Mon Sep 17 00:00:00 2001 From: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Date: Thu, 25 May 2023 10:12:18 -0400 Subject: [PATCH 32/85] Don't differentiate between oxide/stable engines in CHANGELOG --- CHANGELOG.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8585cad4f..84da0cb18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,16 +17,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Add `aria-busy` utility ([#10966](https://github.com/tailwindlabs/tailwindcss/pull/10966)) -- [Oxide] Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205), ([#11260](https://github.com/tailwindlabs/tailwindcss/pull/11260))) -- [Oxide] Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) -- [Oxide] Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) -- [Oxide] Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) +- Support `@import "tailwindcss"` using top-level `index.css` file ([#11205](https://github.com/tailwindlabs/tailwindcss/pull/11205), ([#11260](https://github.com/tailwindlabs/tailwindcss/pull/11260))) +- Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) +- Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) +- Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) ### Changed - Reset padding for `` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) -- [Oxide] Disable color opacity plugins by default in the `oxide` engine ([#10618](https://github.com/tailwindlabs/tailwindcss/pull/10618)) -- [Oxide] Enable relative content paths for the `oxide` engine ([#10621](https://github.com/tailwindlabs/tailwindcss/pull/10621)) - Deprecate `--no-autoprefixer` flag in the CLI ([#11280](https://github.com/tailwindlabs/tailwindcss/pull/11280)) ## [3.3.2] - 2023-04-25 From fd500fcd0c45bd60e84b1c980cdc6a78d6588a8d Mon Sep 17 00:00:00 2001 From: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Date: Fri, 26 May 2023 21:10:02 -0400 Subject: [PATCH 33/85] Exclude variantPlugins from corePluginList This change avoids unnecessarily registering variantPlugins twice. --- src/lib/setupContextUtils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index 017f31170..e8026a50e 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -719,7 +719,7 @@ function collectLayerPlugins(root) { } function resolvePlugins(context, root) { - let corePluginList = Object.entries({ ...variantPlugins, ...corePlugins }) + let corePluginList = Object.entries(corePlugins) .map(([name, plugin]) => { if (!context.tailwindConfig.corePlugins.includes(name)) { return null From 8719be39440a09714a806e71a8c9a8eb5bdce1c9 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Mon, 29 May 2023 06:25:48 +0000 Subject: [PATCH 34/85] Update rollup to version 3.23.0 --- integrations/rollup-sass/package.json | 2 +- integrations/rollup/package.json | 2 +- package-lock.json | 30 +++++++++++++-------------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/integrations/rollup-sass/package.json b/integrations/rollup-sass/package.json index 38f86496a..13b8e2494 100644 --- a/integrations/rollup-sass/package.json +++ b/integrations/rollup-sass/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "rollup": "^3.21.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.62.1" } diff --git a/integrations/rollup/package.json b/integrations/rollup/package.json index 21da41dbd..c927b752a 100644 --- a/integrations/rollup/package.json +++ b/integrations/rollup/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "rollup": "^3.21.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2" } } diff --git a/package-lock.json b/package-lock.json index ad784d3cf..5efeca0cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -92,7 +92,7 @@ "name": "@tailwindcss/integrations-rollup", "version": "0.0.0", "devDependencies": { - "rollup": "^3.21.0", + "rollup": "3.23.0", "rollup-plugin-postcss": "^4.0.2" } }, @@ -100,7 +100,7 @@ "name": "@tailwindcss/integrations-rollup-sass", "version": "0.0.0", "devDependencies": { - "rollup": "^3.21.0", + "rollup": "3.23.0", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.62.1" } @@ -13357,9 +13357,9 @@ } }, "node_modules/rollup": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.0.tgz", - "integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", + "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -19009,14 +19009,14 @@ "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "^3.21.0", + "rollup": "3.23.0", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "^3.21.0", + "rollup": "3.23.0", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.62.1" } @@ -26113,9 +26113,9 @@ } }, "rollup": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.0.tgz", - "integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", + "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -29755,14 +29755,14 @@ "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "^3.21.0", + "rollup": "3.23.0", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "^3.21.0", + "rollup": "3.23.0", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.62.1" } @@ -36859,9 +36859,9 @@ } }, "rollup": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.21.0.tgz", - "integrity": "sha512-ANPhVcyeHvYdQMUyCbczy33nbLzI7RzrBje4uvNiTDJGIMtlKoOStmympwr9OtS1LZxiDmE2wvxHyVhoLtf1KQ==", + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", + "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", "dev": true, "requires": { "fsevents": "~2.3.2" From 820815be0bb74cdbfe589f80ceed439ad2b36aa2 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Tue, 30 May 2023 13:27:15 +0200 Subject: [PATCH 35/85] Remove `autoprefixer` dependency (#11315) * remove `autoprefixer` dependency This was only used in the CLI and we are not using it anymore. The functionality of `autoprefixer` is baked into `lightningcss`. * update changelog --- CHANGELOG.md | 1 + package-lock.json | 111 +++------------------------------------------- package.json | 1 - 3 files changed, 7 insertions(+), 106 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84da0cb18..2bf9d5b78 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Make font settings propagate into buttons, inputs, etc. ([#10940](https://github.com/tailwindlabs/tailwindcss/pull/10940)) - Fix parsing of `theme()` inside `calc()` when there are no spaces around operators ([#11157](https://github.com/tailwindlabs/tailwindcss/pull/11157)) - Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) +- Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) ### Added diff --git a/package-lock.json b/package-lock.json index 5efeca0cf..83058ecbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,7 +49,6 @@ "@swc/core": "^1.3.56", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", @@ -92,7 +91,7 @@ "name": "@tailwindcss/integrations-rollup", "version": "0.0.0", "devDependencies": { - "rollup": "3.23.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2" } }, @@ -100,7 +99,7 @@ "name": "@tailwindcss/integrations-rollup-sass", "version": "0.0.0", "devDependencies": { - "rollup": "3.23.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.62.1" } @@ -5070,39 +5069,6 @@ "node": ">= 4.5.0" } }, - "node_modules/autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/autoprefixer" - } - ], - "dependencies": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - }, - "bin": { - "autoprefixer": "bin/autoprefixer" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, "node_modules/babel-jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", @@ -8291,18 +8257,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fraction.js": { - "version": "4.2.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "patreon", - "url": "https://www.patreon.com/infusion" - } - }, "node_modules/fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -11357,14 +11311,6 @@ "node": ">=0.10.0" } }, - "node_modules/normalize-range": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/normalize-url": { "version": "6.1.0", "dev": true, @@ -19009,14 +18955,14 @@ "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "3.23.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "3.23.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.62.1" } @@ -20086,20 +20032,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, "babel-jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", @@ -22476,10 +22408,6 @@ } } }, - "fraction.js": { - "version": "4.2.0", - "dev": true - }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -24756,10 +24684,6 @@ "normalize-path": { "version": "3.0.0" }, - "normalize-range": { - "version": "0.1.2", - "dev": true - }, "normalize-url": { "version": "6.1.0", "dev": true @@ -27283,7 +27207,6 @@ "@tailwindcss/integrations-webpack-5": "file:integrations/webpack-5", "@tailwindcss/oxide": "file:oxide/crates/node", "arg": "^5.0.2", - "autoprefixer": "^10.4.14", "browserslist": "^4.21.5", "chokidar": "^3.5.3", "concurrently": "^8.0.1", @@ -29755,14 +29678,14 @@ "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "3.23.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "3.23.0", + "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.62.1" } @@ -30832,20 +30755,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "autoprefixer": { - "version": "10.4.14", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.14.tgz", - "integrity": "sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==", - "dev": true, - "requires": { - "browserslist": "^4.21.5", - "caniuse-lite": "^1.0.30001464", - "fraction.js": "^4.2.0", - "normalize-range": "^0.1.2", - "picocolors": "^1.0.0", - "postcss-value-parser": "^4.2.0" - } - }, "babel-jest": { "version": "29.5.0", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", @@ -33222,10 +33131,6 @@ } } }, - "fraction.js": { - "version": "4.2.0", - "dev": true - }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -35502,10 +35407,6 @@ "normalize-path": { "version": "3.0.0" }, - "normalize-range": { - "version": "0.1.2", - "dev": true - }, "normalize-url": { "version": "6.1.0", "dev": true diff --git a/package.json b/package.json index 5a90f70a5..271e8548b 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,6 @@ "@swc/core": "^1.3.56", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", - "autoprefixer": "^10.4.14", "concurrently": "^8.0.1", "eslint": "^8.39.0", "eslint-config-prettier": "^8.8.0", From 7248f2121ea59d73758cb4c76f00fe436ebe932b Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Tue, 30 May 2023 11:58:16 -0400 Subject: [PATCH 36/85] Add `svh`, `lvh`, and `dvh` values to default theme (#11317) * Add svh, lvh, and dvh values to default theme * Update changelog --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com> --- CHANGELOG.md | 1 + stubs/config.full.js | 12 ++++++++++ tests/basic-usage.test.css | 45 ++++++++++++++++++++++++++++++++++++++ tests/basic-usage.test.js | 5 +++-- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2bf9d5b78..e3193b6a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Use `lightningcss` for nesting and vendor prefixes in PostCSS plugin ([#10399](https://github.com/tailwindlabs/tailwindcss/pull/10399)) - Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) - Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) +- Add `svh`, `lvh`, and `dvh` values to default `height`/`min-height`/`max-height` theme ([#11317](https://github.com/tailwindlabs/tailwindcss/pull/11317)) ### Changed diff --git a/stubs/config.full.js b/stubs/config.full.js index 965d2874a..bda7d03ba 100644 --- a/stubs/config.full.js +++ b/stubs/config.full.js @@ -517,6 +517,9 @@ module.exports = { '5/6': '83.333333%', full: '100%', screen: '100vh', + svh: '100svh', + lvh: '100lvh', + dvh: '100dvh', min: 'min-content', max: 'max-content', fit: 'fit-content', @@ -621,6 +624,9 @@ module.exports = { none: 'none', full: '100%', screen: '100vh', + svh: '100svh', + lvh: '100lvh', + dvh: '100dvh', min: 'min-content', max: 'max-content', fit: 'fit-content', @@ -650,6 +656,9 @@ module.exports = { 0: '0px', full: '100%', screen: '100vh', + svh: '100svh', + lvh: '100lvh', + dvh: '100dvh', min: 'min-content', max: 'max-content', fit: 'fit-content', @@ -967,6 +976,9 @@ module.exports = { '11/12': '91.666667%', full: '100%', screen: '100vw', + svw: '100svw', + lvw: '100lvw', + dvw: '100dvw', min: 'min-content', max: 'max-content', fit: 'fit-content', diff --git a/tests/basic-usage.test.css b/tests/basic-usage.test.css index 720c783e9..8d1ba2da8 100644 --- a/tests/basic-usage.test.css +++ b/tests/basic-usage.test.css @@ -201,15 +201,60 @@ .aspect-video { aspect-ratio: 16 / 9; } +.h-0 { + height: 0; +} .h-16 { height: 4rem; } +.h-dvh { + height: 100dvh; +} +.h-full { + height: 100%; +} +.h-lvh { + height: 100lvh; +} +.h-screen { + height: 100vh; +} +.h-svh { + height: 100svh; +} +.max-h-0 { + max-height: 0; +} +.max-h-dvh { + max-height: 100dvh; +} +.max-h-full { + max-height: 100%; +} +.max-h-lvh { + max-height: 100lvh; +} .max-h-screen { max-height: 100vh; } +.max-h-svh { + max-height: 100svh; +} .min-h-0 { min-height: 0; } +.min-h-dvh { + min-height: 100dvh; +} +.min-h-full { + min-height: 100%; +} +.min-h-lvh { + min-height: 100lvh; +} +.min-h-svh { + min-height: 100svh; +} .w-12 { width: 3rem; } diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index 10cdac86d..216ca0600 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -90,9 +90,10 @@ test('basic usage', () => {
-
+ +
-
+
From 69d86873c36fdf5bd3ac21cd7969c02cbe662930 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Tue, 30 May 2023 12:21:08 -0400 Subject: [PATCH 37/85] Add `has-*` variants for `:has(...)` pseudo-class (#11318) * Add `has-*` variants for `:has(...)` pseudo-class * Update changelog * Fix mistake in test --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com> --- CHANGELOG.md | 1 + src/corePlugins.js | 20 +++++ src/lib/setupContextUtils.js | 1 + tests/arbitrary-variants.test.js | 126 +++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e3193b6a9..5b535d888 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix parsing of `theme()` inside `calc()` when there are no spaces around operators ([#11157](https://github.com/tailwindlabs/tailwindcss/pull/11157)) - Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) - Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) +- Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318)) ### Added diff --git a/src/corePlugins.js b/src/corePlugins.js index fc373a77f..15b4e8d03 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -386,6 +386,26 @@ export let variantPlugins = { ) }, + hasVariants: ({ matchVariant }) => { + matchVariant('has', (value) => `&:has(${normalize(value)})`, { values: {} }) + matchVariant( + 'group-has', + (value, { modifier }) => + modifier + ? `:merge(.group\\/${modifier}):has(${normalize(value)}) &` + : `:merge(.group):has(${normalize(value)}) &`, + { values: {} } + ) + matchVariant( + 'peer-has', + (value, { modifier }) => + modifier + ? `:merge(.peer\\/${modifier}):has(${normalize(value)}) ~ &` + : `:merge(.peer):has(${normalize(value)}) ~ &`, + { values: {} } + ) + }, + ariaVariants: ({ matchVariant, theme }) => { matchVariant('aria', (value) => `&[aria-${normalize(value)}]`, { values: theme('aria') ?? {} }) matchVariant( diff --git a/src/lib/setupContextUtils.js b/src/lib/setupContextUtils.js index e8026a50e..0d6bc2509 100644 --- a/src/lib/setupContextUtils.js +++ b/src/lib/setupContextUtils.js @@ -744,6 +744,7 @@ function resolvePlugins(context, root) { let beforeVariants = [ variantPlugins['pseudoElementVariants'], variantPlugins['pseudoClassVariants'], + variantPlugins['hasVariants'], variantPlugins['ariaVariants'], variantPlugins['dataVariants'], ] diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index 1e37a5047..c49376139 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -772,6 +772,132 @@ it('should support supports', () => { }) }) +test('has-* variants with arbitrary values', () => { + let config = { + theme: {}, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .has-\[\.foo\:hover\]\:block:has(.foo:hover) { + display: block; + } + .has-\[figcaption\]\:inline-block:has(figcaption) { + display: inline-block; + } + .has-\[\[data-active\]\]\:inline:has([data-active]) { + display: inline; + } + .has-\[\.foo\]\:flex:has(.foo) { + display: flex; + } + .has-\[\>_\.potato\]\:table:has(> .potato) { + display: table; + } + .has-\[\+_h2\]\:grid:has(+ h2) { + display: grid; + } + .has-\[\>_h1_\+_h2\]\:contents:has(> h1 + h2) { + display: contents; + } + .has-\[h2\]\:has-\[\.banana\]\:hidden:has(.banana):has(h2) { + display: none; + } + `) + }) +}) + +test('group-has-* variants with arbitrary values', () => { + let config = { + theme: {}, + content: [ + { + raw: html` +
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .group:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\:block { + display: block; + } + .group\/two:has(> h1 + .foo) .group-has-\[\>_h1_\+_\.foo\]\/two\:flex { + display: flex; + } + `) + }) +}) + +test('peer-has-* variants with arbitrary values', () => { + let config = { + theme: {}, + content: [ + { + raw: html` +
+
+
+
+
+
+
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = css` + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .peer:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\:block { + display: block; + } + .peer\/two:has(> h1 + .foo) ~ .peer-has-\[\>_h1_\+_\.foo\]\/two\:flex { + display: flex; + } + `) + }) +}) + it('should be possible to use modifiers and arbitrary groups', () => { let config = { content: [ From e1d49554312b07c3f44ae655f32575b936d7faa4 Mon Sep 17 00:00:00 2001 From: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Date: Tue, 30 May 2023 12:21:51 -0400 Subject: [PATCH 38/85] Move entry in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b535d888..8199cf115 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,7 +14,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix parsing of `theme()` inside `calc()` when there are no spaces around operators ([#11157](https://github.com/tailwindlabs/tailwindcss/pull/11157)) - Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) - Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) -- Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318)) ### Added @@ -24,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Automatically detect content paths when no `content` configuration is provided ([#11173](https://github.com/tailwindlabs/tailwindcss/pull/11173), [#11221](https://github.com/tailwindlabs/tailwindcss/pull/11221)) - Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) - Add `svh`, `lvh`, and `dvh` values to default `height`/`min-height`/`max-height` theme ([#11317](https://github.com/tailwindlabs/tailwindcss/pull/11317)) +- Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318)) ### Changed From cb1a0e1a9568d597d6e65864aa3017736707888e Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Tue, 30 May 2023 15:26:27 -0400 Subject: [PATCH 39/85] Add support for `text-wrap` property (#11320) Update changelog Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com> --- CHANGELOG.md | 1 + src/corePlugins.js | 8 ++++++++ tests/basic-usage.test.css | 9 +++++++++ tests/basic-usage.test.js | 1 + 4 files changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8199cf115..5aa43abd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Process and inline `@import` at-rules natively ([#11239](https://github.com/tailwindlabs/tailwindcss/pull/11239)) - Add `svh`, `lvh`, and `dvh` values to default `height`/`min-height`/`max-height` theme ([#11317](https://github.com/tailwindlabs/tailwindcss/pull/11317)) - Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318)) +- Add `text-wrap` utilities including `text-balance` ([#11320](https://github.com/tailwindlabs/tailwindcss/pull/11320)) ### Changed diff --git a/src/corePlugins.js b/src/corePlugins.js index 15b4e8d03..00ceab259 100644 --- a/src/corePlugins.js +++ b/src/corePlugins.js @@ -1523,6 +1523,14 @@ export let corePlugins = { }) }, + textWrap: ({ addUtilities }) => { + addUtilities({ + '.text-wrap': { 'text-wrap': 'wrap' }, + '.text-nowrap': { 'text-wrap': 'nowrap' }, + '.text-balance': { 'text-wrap': 'balance' }, + }) + }, + wordBreak: ({ addUtilities }) => { addUtilities({ '.break-normal': { 'overflow-wrap': 'normal', 'word-break': 'normal' }, diff --git a/tests/basic-usage.test.css b/tests/basic-usage.test.css index 8d1ba2da8..80c406bf6 100644 --- a/tests/basic-usage.test.css +++ b/tests/basic-usage.test.css @@ -597,6 +597,15 @@ .whitespace-nowrap { white-space: nowrap; } +.text-wrap { + text-wrap: wrap; +} +.text-nowrap { + text-wrap: nowrap; +} +.text-balance { + text-wrap: balance; +} .break-words { overflow-wrap: break-word; } diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index 216ca0600..c34ba8aee 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -192,6 +192,7 @@ test('basic usage', () => {
+
From c9138b2e0be21cf5337944a22f0cd92417d1b72b Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 31 May 2023 13:44:28 +0200 Subject: [PATCH 40/85] bump napi-rs (#11328) --- oxide/Cargo.lock | 448 +++++++++++++++++++-------------- oxide/crates/node/package.json | 2 +- oxide/crates/node/src/lib.rs | 2 +- package-lock.json | 24 +- 4 files changed, 268 insertions(+), 208 deletions(-) diff --git a/oxide/Cargo.lock b/oxide/Cargo.lock index 948b8b4cc..06f4e1b6e 100644 --- a/oxide/Cargo.lock +++ b/oxide/Cargo.lock @@ -11,6 +11,64 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" + +[[package]] +name = "anstyle-parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys 0.48.0", +] + [[package]] name = "atty" version = "0.2.14" @@ -35,22 +93,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "bstr" -version = "0.2.17" +name = "bitflags" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] +checksum = "6776fc96284a0bb647b615056fc496d1fe1644a7ab01829818a6d91cae888b84" [[package]] name = "bstr" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" dependencies = [ "memchr", "once_cell", @@ -60,9 +112,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -94,47 +146,58 @@ version = "2.34.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ - "bitflags", + "bitflags 1.3.2", "textwrap", "unicode-width", ] [[package]] name = "clap" -version = "4.0.26" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc" dependencies = [ - "atty", - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990" +dependencies = [ + "anstream", + "anstyle", + "bitflags 1.3.2", + "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "convert_case" @@ -197,9 +260,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -207,9 +270,9 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if", "crossbeam-epoch", @@ -218,9 +281,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", @@ -241,22 +304,21 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] [[package]] name = "csv" -version = "1.1.6" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" dependencies = [ - "bstr 0.2.17", "csv-core", - "itoa 0.4.8", + "itoa", "ryu", "serde", ] @@ -272,19 +334,19 @@ dependencies = [ [[package]] name = "ctor" -version = "0.1.26" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +checksum = "990a40740adf249724a6000c0fc4bd574712f50bb17c2d6f6cec837ae2f0ee75" dependencies = [ "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "errno" @@ -337,8 +399,8 @@ version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" dependencies = [ - "aho-corasick", - "bstr 1.4.0", + "aho-corasick 0.7.20", + "bstr", "fnv", "log", "regex", @@ -350,7 +412,7 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93e3af942408868f6934a7b85134a3230832b9977cf66125df2f9edcfce4ddcc" dependencies = [ - "bitflags", + "bitflags 1.3.2", "ignore", "walkdir", ] @@ -363,9 +425,9 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" @@ -376,6 +438,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.3.1" @@ -410,15 +481,27 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", "windows-sys 0.48.0", ] +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + [[package]] name = "itertools" version = "0.10.5" @@ -430,21 +513,15 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.8" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -457,9 +534,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.142" +version = "0.2.144" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" [[package]] name = "libloading" @@ -473,18 +550,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "log" -version = "0.4.17" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "matchers" @@ -503,24 +577,24 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.7.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] [[package]] name = "napi" -version = "2.10.1" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "466b16c759694cb07fbb023b0bde55afcc2ae35e8c0264b070c86a3e9a18cb6c" +checksum = "d7f0a2e93526dd9c8c522d72a4d0c88678be8966fabe9fb8f2947fde6339b682" dependencies = [ - "bitflags", + "bitflags 2.3.1", "ctor", + "napi-derive", "napi-sys", "once_cell", - "thread_local", ] [[package]] @@ -531,36 +605,38 @@ checksum = "882a73d9ef23e8dc2ebbffb6a6ae2ef467c0f18ac10711e4cc59c5485d41df0e" [[package]] name = "napi-derive" -version = "2.11.2" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e367c72b3f0243d490f0cf4feed9a28e40e4e9cba16912951dbeccf6c607576" +checksum = "da1c6a8fa84d549aa8708fcd062372bf8ec6e849de39016ab921067d21bde367" dependencies = [ + "cfg-if", "convert_case", "napi-derive-backend", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "napi-derive-backend" -version = "1.0.45" +version = "1.0.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2cf4ba5f1f6d51b9b5e2d809e229201f3aa14f198d58ec9ba4ecf82dbabb381" +checksum = "20bbc7c69168d06a848f925ec5f0e0997f98e8c8d4f2cc30157f0da51c009e17" dependencies = [ "convert_case", "once_cell", "proc-macro2", "quote", "regex", - "syn", + "semver", + "syn 1.0.109", ] [[package]] name = "napi-sys" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529671ebfae679f2ce9630b62dd53c72c56b3eb8b2c852e7e2fa91704ff93d67" +checksum = "166b5ef52a3ab5575047a9fe8d4a030cdd0f63c96f071cd6907674453b07bae3" dependencies = [ "libloading", ] @@ -586,19 +662,19 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" [[package]] name = "oorandom" @@ -606,12 +682,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "overload" version = "0.1.1" @@ -652,64 +722,39 @@ dependencies = [ "plotters-backend", ] -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] [[package]] name = "rayon" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e060280438193c554f654141c9ea9417886713b7acd75974c85b18a69a88e0b" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" dependencies = [ - "crossbeam-deque", "either", "rayon-core", ] [[package]] name = "rayon-core" -version = "1.10.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" dependencies = [ "crossbeam-channel", "crossbeam-deque", @@ -723,18 +768,18 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "regex" -version = "1.7.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390" dependencies = [ - "aho-corasick", + "aho-corasick 1.0.1", "memchr", - "regex-syntax", + "regex-syntax 0.7.2", ] [[package]] @@ -743,14 +788,20 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rustix" @@ -758,7 +809,7 @@ version = "0.37.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", @@ -768,9 +819,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "same-file" @@ -788,10 +839,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "serde" -version = "1.0.147" +name = "semver" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" [[package]] name = "serde_cbor" @@ -805,22 +862,22 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.163" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ - "itoa 1.0.4", + "itoa", "ryu", "serde", ] @@ -848,9 +905,20 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -876,7 +944,7 @@ version = "0.1.0" name = "tailwindcss-core" version = "0.1.0" dependencies = [ - "bstr 1.4.0", + "bstr", "criterion", "crossbeam", "fxhash", @@ -894,7 +962,7 @@ dependencies = [ name = "tailwindcss-oxide" version = "0.1.0" dependencies = [ - "clap 4.0.26", + "clap 4.3.0", "rayon", "tailwindcss-core", ] @@ -912,15 +980,6 @@ dependencies = [ "windows-sys 0.45.0", ] -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - [[package]] name = "textwrap" version = "0.11.0" @@ -932,10 +991,11 @@ dependencies = [ [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] @@ -963,20 +1023,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -995,9 +1055,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -1013,9 +1073,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-segmentation" @@ -1029,18 +1089,18 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - [[package]] name = "walkdir" version = "2.3.3" @@ -1053,9 +1113,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1063,24 +1123,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1088,28 +1148,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", diff --git a/oxide/crates/node/package.json b/oxide/crates/node/package.json index 80ddc6fcf..72589305f 100644 --- a/oxide/crates/node/package.json +++ b/oxide/crates/node/package.json @@ -19,7 +19,7 @@ }, "license": "MIT", "devDependencies": { - "@napi-rs/cli": "2.15.2" + "@napi-rs/cli": "^2.16.1" }, "engines": { "node": ">= 10" diff --git a/oxide/crates/node/src/lib.rs b/oxide/crates/node/src/lib.rs index 82bf28b0a..343a6e367 100644 --- a/oxide/crates/node/src/lib.rs +++ b/oxide/crates/node/src/lib.rs @@ -1,4 +1,4 @@ -use napi::bindgen_prelude::ToNapiValue; +use napi::bindgen_prelude::{FromNapiValue, ToNapiValue}; use std::path::PathBuf; #[macro_use] diff --git a/package-lock.json b/package-lock.json index 83058ecbc..4a5c885f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2497,9 +2497,9 @@ ] }, "node_modules/@napi-rs/cli": { - "version": "2.15.2", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.15.2.tgz", - "integrity": "sha512-80tBCtCnEhAmFtB9oPM0FL74uW7fAmtpeqjvERH7Q1z/aZzCAs/iNfE7U3ehpwg9Q07Ob2Eh/+1guyCdX/p24w==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.16.1.tgz", + "integrity": "sha512-L0Gr5iEQIDEbvWdDr1HUaBOxBSHL1VZhWSk1oryawoT8qJIY+KGfLFelU+Qma64ivCPbxYpkfPoKYVG3rcoGIA==", "dev": true, "bin": { "napi": "scripts/index.js" @@ -16500,7 +16500,7 @@ "version": "0.0.0", "license": "MIT", "devDependencies": { - "@napi-rs/cli": "2.15.2" + "@napi-rs/cli": "^2.16.1" }, "engines": { "node": ">= 10" @@ -17852,9 +17852,9 @@ "optional": true }, "@napi-rs/cli": { - "version": "2.15.2", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.15.2.tgz", - "integrity": "sha512-80tBCtCnEhAmFtB9oPM0FL74uW7fAmtpeqjvERH7Q1z/aZzCAs/iNfE7U3ehpwg9Q07Ob2Eh/+1guyCdX/p24w==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.16.1.tgz", + "integrity": "sha512-L0Gr5iEQIDEbvWdDr1HUaBOxBSHL1VZhWSk1oryawoT8qJIY+KGfLFelU+Qma64ivCPbxYpkfPoKYVG3rcoGIA==", "dev": true }, "@nodelib/fs.scandir": { @@ -19281,7 +19281,7 @@ "@tailwindcss/oxide": { "version": "file:oxide/crates/node", "requires": { - "@napi-rs/cli": "2.15.2", + "@napi-rs/cli": "^2.16.1", "@tailwindcss/oxide-darwin-arm64": "0.0.0", "@tailwindcss/oxide-darwin-x64": "0.0.0", "@tailwindcss/oxide-freebsd-x64": "0.0.0", @@ -28575,9 +28575,9 @@ "optional": true }, "@napi-rs/cli": { - "version": "2.15.2", - "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.15.2.tgz", - "integrity": "sha512-80tBCtCnEhAmFtB9oPM0FL74uW7fAmtpeqjvERH7Q1z/aZzCAs/iNfE7U3ehpwg9Q07Ob2Eh/+1guyCdX/p24w==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@napi-rs/cli/-/cli-2.16.1.tgz", + "integrity": "sha512-L0Gr5iEQIDEbvWdDr1HUaBOxBSHL1VZhWSk1oryawoT8qJIY+KGfLFelU+Qma64ivCPbxYpkfPoKYVG3rcoGIA==", "dev": true }, "@nodelib/fs.scandir": { @@ -30004,7 +30004,7 @@ "@tailwindcss/oxide": { "version": "file:oxide/crates/node", "requires": { - "@napi-rs/cli": "2.15.2", + "@napi-rs/cli": "^2.16.1", "@tailwindcss/oxide-darwin-arm64": "0.0.0", "@tailwindcss/oxide-darwin-x64": "0.0.0", "@tailwindcss/oxide-freebsd-x64": "0.0.0", From ecebde1d521f1d567fee6e6bd3348234d97f33e1 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 31 May 2023 15:31:16 +0200 Subject: [PATCH 41/85] bump napi-rs in Cargo.toml --- oxide/crates/node/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oxide/crates/node/Cargo.toml b/oxide/crates/node/Cargo.toml index 54995fa9e..0ded64922 100644 --- a/oxide/crates/node/Cargo.toml +++ b/oxide/crates/node/Cargo.toml @@ -8,8 +8,8 @@ crate-type = ["cdylib"] [dependencies] # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix -napi = { version = "2.10.0", default-features = false, features = ["napi4"] } -napi-derive = "2.11.1" +napi = { version = "2.13.1", default-features = false, features = ["napi4"] } +napi-derive = "2.13.0" tailwindcss-core = { path = "../core" } rayon = "1.5.3" From 352c563d991f10f2cbf455d1dda999b00f5e86bd Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 31 May 2023 18:28:11 +0200 Subject: [PATCH 42/85] Fix source maps issue resulting in a crash (#11319) * only try to pretty print `err.source` if it exists * fix small typo * drop unnecessary path resolving * add `from` and `to` to `run` test helper * enable all source map tests * ensure source maps are generated properly * update annotation values in tests * handle `map: true` * add test for `map: { inline: true }` * force Lightning CSS to handle an inline source map * base64 encode the test name This will get rid of special characters that can cause issues / confusion when debugging tests. * ensure utilities and components with variants are pointing to the correct source Co-authored-by: Jordan Pittman * update changelog --------- Co-authored-by: Jordan Pittman --- CHANGELOG.md | 1 + src/lib/expandTailwindAtRules.js | 18 +- src/plugin.js | 42 +- tests/source-maps.test.js | 741 +++++++++++++++---------------- tests/util/run.js | 20 +- tests/util/source-maps.js | 13 +- 6 files changed, 419 insertions(+), 416 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5aa43abd2..46498cc9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fix parsing of `theme()` inside `calc()` when there are no spaces around operators ([#11157](https://github.com/tailwindlabs/tailwindcss/pull/11157)) - Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) - Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) +- Fix source maps issue resulting in a crash ([#11319](https://github.com/tailwindlabs/tailwindcss/pull/11319)) ### Added diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index c3fbc8cc2..34257e148 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -246,11 +246,21 @@ export default function expandTailwindAtRules(context) { ) layerNodes.variants.remove() } else if (variantNodes.length > 0) { - root.append( - cloneNodes(variantNodes, root.source, { - layer: 'variants', + let cloned = cloneNodes(variantNodes, undefined, { + layer: 'variants', + }) + + cloned.forEach((node) => { + let parentLayer = node.raws.tailwind?.parentLayer ?? null + + node.walk((n) => { + if (!n.source) { + n.source = layerNodes[parentLayer].source + } }) - ) + }) + + root.append(cloned) } // If we've got a utility layer and no utilities are generated there's likely something wrong diff --git a/src/plugin.js b/src/plugin.js index 4356add62..3c62c1913 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -40,38 +40,52 @@ module.exports = function tailwindcss(configOrPath) { processTailwindFeatures(context)(root, result) }, function lightningCssPlugin(_root, result) { + let map = result.map ?? result.opts.map + + let intermediateResult = result.root.toResult({ + map: map ? { inline: true } : false, + }) + let intermediateMap = intermediateResult.map?.toJSON?.() ?? map + try { let transformed = lightningcss.transform({ filename: result.opts.from, - code: Buffer.from(result.root.toString()), + code: Buffer.from(intermediateResult.css), minify: false, - sourceMap: !!result.map, - inputSourceMap: result.map ? result.map.toString() : undefined, + sourceMap: !!intermediateMap, targets: typeof process !== 'undefined' && process.env.JEST_WORKER_ID ? { chrome: 111 << 16 } : lightningcss.browserslistToTargets( browserslist(require('../package.json').browserslist) ), - drafts: { nesting: true, customMedia: true, }, }) - result.map = Object.assign(result.map ?? {}, { - toJSON() { - return transformed.map.toJSON() - }, - toString() { - return transformed.map.toString() - }, - }) + let code = transformed.code.toString() - result.root = postcss.parse(transformed.code.toString('utf8')) + // https://postcss.org/api/#sourcemapoptions + if (intermediateMap && transformed.map != null) { + let prev = transformed.map.toString() + + if (typeof intermediateMap === 'object') { + intermediateMap.prev = prev + } else { + code = `${code}\n/*# sourceMappingURL=data:application/json;base64,${Buffer.from( + prev + ).toString('base64')} */` + } + } + + result.root = postcss.parse(code, { + ...result.opts, + map: intermediateMap, + }) } catch (err) { - if (typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { + if (err.source && typeof process !== 'undefined' && process.env.JEST_WORKER_ID) { let lines = err.source.split('\n') err = new Error( [ diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index 5f3a99902..1a99252f5 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -2,7 +2,7 @@ import postcss from 'postcss' import { parseSourceMaps } from './util/source-maps' import { runWithSourceMaps as run, html, css, map } from './util/run' -test.skip('apply generates source maps', async () => { +test('apply generates source maps', async () => { let config = { content: [ { @@ -38,33 +38,34 @@ test.skip('apply generates source maps', async () => { // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') - expect(sources.length).toBe(1) + expect(sources.length).toBe(2) - expect(annotations).toEqual([ - '2:6 -> 2:6', - '3:8-29 -> 3:8-29', - '4:8-35 -> 4:8-20', - '4:8-35 -> 5:8-19', - '4:8-35 -> 6:8-26', - '4:8-35 -> 7:8-63', - '5:6 -> 8:6', - '7:6 -> 10:6', - '8:8-41 -> 11:8-41', - '9:8-33 -> 12:8-20', - '9:8-33 -> 13:8-19', - '9:8-33 -> 14:8-26', - '9:8-33 -> 15:8-63', - '10:6 -> 16:6', - '13:8 -> 18:6', - '13:8-31 -> 19:8-20', - '13:8-31 -> 20:8-19', - '13:8-31 -> 21:8-26', - '13:8 -> 22:8', - '13:31 -> 23:0', - ]) + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-14 -> 2:2-14", + "3:2-13 -> 3:2-13", + "4:2-20 -> 4:2-20", + "5:2-23 -> 5:2-23", + "6:2-57 -> 6:2-57", + "7:0 -> 7:0", + "7:4 -> 9:0", + "10:2-14 -> 10:2-14", + "11:2-13 -> 11:2-13", + "12:2-20 -> 12:2-20", + "13:2-57 -> 13:2-57", + "14:0 -> 14:0", + "13:6 -> 16:0", + "17:2-14 -> 17:2-14", + "18:2-13 -> 18:2-13", + "19:2-20 -> 19:2-20", + "20:2-53 -> 20:2-53", + "21:0 -> 21:0", + ] + `) }) -test.skip('preflight + base have source maps', async () => { +test('preflight + base have source maps', async () => { let config = { content: [], } @@ -79,325 +80,213 @@ test.skip('preflight + base have source maps', async () => { // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') - expect(sources.length).toBe(1) + expect(sources.length).toBe(2) - expect(annotations).toEqual([ - '2:6 -> 1:0', - '2:20-6 -> 3:1-2', - '2:20 -> 6:1', - '2:6 -> 8:0', - '2:6-20 -> 11:2-32', - '2:6-20 -> 12:2-25', - '2:6-20 -> 13:2-29', - '2:6-20 -> 14:2-31', - '2:20 -> 15:0', - '2:6 -> 17:0', - '2:6-20 -> 19:2-18', - '2:20 -> 20:0', - '2:6 -> 22:0', - '2:20 -> 29:1', - '2:6 -> 31:0', - '2:6-20 -> 32:2-26', - '2:6-20 -> 33:2-40', - '2:6-20 -> 34:2-26', - '2:6-20 -> 35:2-21', - '2:6-20 -> 36:2-230', - '2:6-20 -> 37:2-39', - '2:6-20 -> 38:2-41', - '2:20 -> 39:0', - '2:6 -> 41:0', - '2:20 -> 44:1', - '2:6 -> 46:0', - '2:6-20 -> 47:2-19', - '2:6-20 -> 48:2-30', - '2:20 -> 49:0', - '2:6 -> 51:0', - '2:20 -> 55:1', - '2:6 -> 57:0', - '2:6-20 -> 58:2-19', - '2:6-20 -> 59:2-24', - '2:6-20 -> 60:2-31', - '2:20 -> 61:0', - '2:6 -> 63:0', - '2:20 -> 65:1', - '2:6 -> 67:0', - '2:6-20 -> 68:2-35', - '2:20 -> 69:0', - '2:6 -> 71:0', - '2:20 -> 73:1', - '2:6 -> 75:0', - '2:6-20 -> 81:2-20', - '2:6-20 -> 82:2-22', - '2:20 -> 83:0', - '2:6 -> 85:0', - '2:20 -> 87:1', - '2:6 -> 89:0', - '2:6-20 -> 90:2-16', - '2:6-20 -> 91:2-26', - '2:20 -> 92:0', - '2:6 -> 94:0', - '2:20 -> 96:1', - '2:6 -> 98:0', - '2:6-20 -> 100:2-21', - '2:20 -> 101:0', - '2:6 -> 103:0', - '2:20 -> 106:1', - '2:6 -> 108:0', - '2:6-20 -> 112:2-121', - '2:6-20 -> 113:2-24', - '2:20 -> 114:0', - '2:6 -> 116:0', - '2:20 -> 118:1', - '2:6 -> 120:0', - '2:6-20 -> 121:2-16', - '2:20 -> 122:0', - '2:6 -> 124:0', - '2:20 -> 126:1', - '2:6 -> 128:0', - '2:6-20 -> 130:2-16', - '2:6-20 -> 131:2-16', - '2:6-20 -> 132:2-20', - '2:6-20 -> 133:2-26', - '2:20 -> 134:0', - '2:6 -> 136:0', - '2:6-20 -> 137:2-17', - '2:20 -> 138:0', - '2:6 -> 140:0', - '2:6-20 -> 141:2-13', - '2:20 -> 142:0', - '2:6 -> 144:0', - '2:20 -> 148:1', - '2:6 -> 150:0', - '2:6-20 -> 151:2-24', - '2:6-20 -> 152:2-31', - '2:6-20 -> 153:2-35', - '2:20 -> 154:0', - '2:6 -> 156:0', - '2:20 -> 160:1', - '2:6 -> 162:0', - '2:6-20 -> 167:2-30', - '2:6-20 -> 168:2-40', - '2:6-20 -> 169:2-42', - '2:6-20 -> 170:2-25', - '2:6-20 -> 171:2-30', - '2:6-20 -> 172:2-30', - '2:6-20 -> 173:2-24', - '2:6-20 -> 174:2-19', - '2:6-20 -> 175:2-20', - '2:20 -> 176:0', - '2:6 -> 178:0', - '2:20 -> 180:1', - '2:6 -> 182:0', - '2:6-20 -> 184:2-22', - '2:20 -> 185:0', - '2:6 -> 187:0', - '2:20 -> 190:1', - '2:6 -> 192:0', - '2:6-20 -> 196:2-36', - '2:6-20 -> 197:2-39', - '2:6-20 -> 198:2-32', - '2:20 -> 199:0', - '2:6 -> 201:0', - '2:20 -> 203:1', - '2:6 -> 205:0', - '2:6-20 -> 206:2-15', - '2:20 -> 207:0', - '2:6 -> 209:0', - '2:20 -> 211:1', - '2:6 -> 213:0', - '2:6-20 -> 214:2-18', - '2:20 -> 215:0', - '2:6 -> 217:0', - '2:20 -> 219:1', - '2:6 -> 221:0', - '2:6-20 -> 222:2-26', - '2:20 -> 223:0', - '2:6 -> 225:0', - '2:20 -> 227:1', - '2:6 -> 229:0', - '2:6-20 -> 231:2-14', - '2:20 -> 232:0', - '2:6 -> 234:0', - '2:20 -> 237:1', - '2:6 -> 239:0', - '2:6-20 -> 240:2-39', - '2:6-20 -> 241:2-30', - '2:20 -> 242:0', - '2:6 -> 244:0', - '2:20 -> 246:1', - '2:6 -> 248:0', - '2:6-20 -> 249:2-26', - '2:20 -> 250:0', - '2:6 -> 252:0', - '2:20 -> 255:1', - '2:6 -> 257:0', - '2:6-20 -> 258:2-36', - '2:6-20 -> 259:2-23', - '2:20 -> 260:0', - '2:6 -> 262:0', - '2:20 -> 264:1', - '2:6 -> 266:0', - '2:6-20 -> 267:2-20', - '2:20 -> 268:0', - '2:6 -> 270:0', - '2:20 -> 272:1', - '2:6 -> 274:0', - '2:6-20 -> 287:2-11', - '2:20 -> 288:0', - '2:6 -> 290:0', - '2:6-20 -> 291:2-11', - '2:6-20 -> 292:2-12', - '2:20 -> 293:0', - '2:6 -> 295:0', - '2:6-20 -> 296:2-12', - '2:20 -> 297:0', - '2:6 -> 299:0', - '2:6-20 -> 302:2-18', - '2:6-20 -> 303:2-11', - '2:6-20 -> 304:2-12', - '2:20 -> 305:0', - '2:6 -> 307:0', - '2:6-20 -> 308:2-12', - '2:20 -> 309:0', - '2:6 -> 311:0', - '2:20 -> 313:1', - '2:6 -> 315:0', - '2:6-20 -> 316:2-18', - '2:20 -> 317:0', - '2:6 -> 319:0', - '2:20 -> 322:1', - '2:6 -> 324:0', - '2:6-20 -> 326:2-20', - '2:6-20 -> 327:2-24', - '2:20 -> 328:0', - '2:6 -> 330:0', - '2:20 -> 332:1', - '2:6 -> 334:0', - '2:6-20 -> 336:2-17', - '2:20 -> 337:0', - '2:6 -> 339:0', - '2:20 -> 341:1', - '2:6 -> 342:0', - '2:6-20 -> 343:2-17', - '2:20 -> 344:0', - '2:6 -> 346:0', - '2:20 -> 350:1', - '2:6 -> 352:0', - '2:6-20 -> 360:2-24', - '2:6-20 -> 361:2-32', - '2:20 -> 362:0', - '2:6 -> 364:0', - '2:20 -> 366:1', - '2:6 -> 368:0', - '2:6-20 -> 370:2-17', - '2:6-20 -> 371:2-14', - '2:20 -> 372:0', - '2:6-20 -> 374:0-72', - '2:6 -> 375:0', - '2:6-20 -> 376:2-15', - '2:20 -> 377:0', - '2:6 -> 379:0', - '2:6-20 -> 380:2-26', - '2:6-20 -> 381:2-26', - '2:6-20 -> 382:2-21', - '2:6-20 -> 383:2-21', - '2:6-20 -> 384:2-16', - '2:6-20 -> 385:2-16', - '2:6-20 -> 386:2-16', - '2:6-20 -> 387:2-17', - '2:6-20 -> 388:2-17', - '2:6-20 -> 389:2-15', - '2:6-20 -> 390:2-15', - '2:6-20 -> 391:2-20', - '2:6-20 -> 392:2-40', - '2:6-20 -> 393:2-32', - '2:6-20 -> 394:2-31', - '2:6-20 -> 395:2-30', - '2:6-20 -> 396:2-17', - '2:6-20 -> 397:2-22', - '2:6-20 -> 398:2-24', - '2:6-20 -> 399:2-25', - '2:6-20 -> 400:2-26', - '2:6-20 -> 401:2-20', - '2:6-20 -> 402:2-29', - '2:6-20 -> 403:2-30', - '2:6-20 -> 404:2-40', - '2:6-20 -> 405:2-36', - '2:6-20 -> 406:2-29', - '2:6-20 -> 407:2-24', - '2:6-20 -> 408:2-32', - '2:6-20 -> 409:2-14', - '2:6-20 -> 410:2-20', - '2:6-20 -> 411:2-18', - '2:6-20 -> 412:2-19', - '2:6-20 -> 413:2-20', - '2:6-20 -> 414:2-16', - '2:6-20 -> 415:2-18', - '2:6-20 -> 416:2-15', - '2:6-20 -> 417:2-21', - '2:6-20 -> 418:2-23', - '2:6-20 -> 419:2-29', - '2:6-20 -> 420:2-27', - '2:6-20 -> 421:2-28', - '2:6-20 -> 422:2-29', - '2:6-20 -> 423:2-25', - '2:6-20 -> 424:2-26', - '2:6-20 -> 425:2-27', - '2:6 -> 426:2', - '2:20 -> 427:0', - '2:6 -> 429:0', - '2:6-20 -> 430:2-26', - '2:6-20 -> 431:2-26', - '2:6-20 -> 432:2-21', - '2:6-20 -> 433:2-21', - '2:6-20 -> 434:2-16', - '2:6-20 -> 435:2-16', - '2:6-20 -> 436:2-16', - '2:6-20 -> 437:2-17', - '2:6-20 -> 438:2-17', - '2:6-20 -> 439:2-15', - '2:6-20 -> 440:2-15', - '2:6-20 -> 441:2-20', - '2:6-20 -> 442:2-40', - '2:6-20 -> 443:2-32', - '2:6-20 -> 444:2-31', - '2:6-20 -> 445:2-30', - '2:6-20 -> 446:2-17', - '2:6-20 -> 447:2-22', - '2:6-20 -> 448:2-24', - '2:6-20 -> 449:2-25', - '2:6-20 -> 450:2-26', - '2:6-20 -> 451:2-20', - '2:6-20 -> 452:2-29', - '2:6-20 -> 453:2-30', - '2:6-20 -> 454:2-40', - '2:6-20 -> 455:2-36', - '2:6-20 -> 456:2-29', - '2:6-20 -> 457:2-24', - '2:6-20 -> 458:2-32', - '2:6-20 -> 459:2-14', - '2:6-20 -> 460:2-20', - '2:6-20 -> 461:2-18', - '2:6-20 -> 462:2-19', - '2:6-20 -> 463:2-20', - '2:6-20 -> 464:2-16', - '2:6-20 -> 465:2-18', - '2:6-20 -> 466:2-15', - '2:6-20 -> 467:2-21', - '2:6-20 -> 468:2-23', - '2:6-20 -> 469:2-29', - '2:6-20 -> 470:2-27', - '2:6-20 -> 471:2-28', - '2:6-20 -> 472:2-29', - '2:6-20 -> 473:2-25', - '2:6-20 -> 474:2-26', - '2:6-20 -> 475:2-27', - '2:6 -> 476:2', - '2:20 -> 477:0', - ]) + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-24 -> 2:2-24", + "3:2-25 -> 3:2-25", + "4:0 -> 4:0", + "2:4 -> 6:0", + "7:2-18 -> 7:2-18", + "8:0 -> 8:0", + "2:4 -> 10:0", + "11:2-32 -> 11:2-32", + "12:2-13 -> 12:2-13", + "13:2-31 -> 13:2-31", + "14:2-33 -> 14:2-33", + "15:2-208 -> 15:2-208", + "16:2-18 -> 16:2-18", + "17:0 -> 17:0", + "2:4 -> 19:0", + "20:2-22 -> 20:2-22", + "21:2-11 -> 21:2-11", + "22:0 -> 22:0", + "2:4 -> 24:0", + "25:2-11 -> 25:2-11", + "26:2-16 -> 26:2-16", + "27:2-23 -> 27:2-23", + "28:0 -> 28:0", + "2:4 -> 30:0", + "31:2-35 -> 31:2-35", + "32:0 -> 32:0", + "2:4 -> 34:0", + "35:2-20 -> 35:2-20", + "36:2-22 -> 36:2-22", + "37:0 -> 37:0", + "2:4 -> 39:0", + "40:2-16 -> 40:2-16", + "41:2-26 -> 41:2-26", + "42:0 -> 42:0", + "2:4 -> 44:0", + "45:2-21 -> 45:2-21", + "46:0 -> 46:0", + "2:4 -> 48:0", + "49:2-109 -> 49:2-109", + "50:2-16 -> 50:2-16", + "51:0 -> 51:0", + "2:4 -> 53:0", + "54:2-16 -> 54:2-16", + "55:0 -> 55:0", + "2:4 -> 57:0", + "58:2-26 -> 58:2-26", + "59:2-16 -> 59:2-16", + "60:2-16 -> 60:2-16", + "61:2-20 -> 61:2-20", + "62:0 -> 62:0", + "2:4 -> 64:0", + "65:2-16 -> 65:2-16", + "66:0 -> 66:0", + "2:4 -> 68:0", + "69:2-12 -> 69:2-12", + "70:0 -> 70:0", + "2:4 -> 72:0", + "73:2-16 -> 73:2-16", + "74:2-23 -> 74:2-23", + "75:2-27 -> 75:2-27", + "76:0 -> 76:0", + "2:4 -> 78:0", + "79:2-32 -> 79:2-32", + "80:2-34 -> 80:2-34", + "81:2-22 -> 81:2-22", + "82:2-17 -> 82:2-17", + "83:2-22 -> 83:2-22", + "84:2-22 -> 84:2-22", + "85:2-16 -> 85:2-16", + "86:2-11 -> 86:2-11", + "87:2-12 -> 87:2-12", + "88:0 -> 88:0", + "2:4 -> 90:0", + "91:2-22 -> 91:2-22", + "92:0 -> 92:0", + "2:4 -> 94:0", + "95:2-28 -> 95:2-28", + "96:2-25 -> 96:2-25", + "97:2-24 -> 97:2-24", + "98:0 -> 98:0", + "2:4 -> 100:0", + "101:2-15 -> 101:2-15", + "102:0 -> 102:0", + "2:4 -> 104:0", + "105:2-18 -> 105:2-18", + "106:0 -> 106:0", + "2:4 -> 108:0", + "109:2-26 -> 109:2-26", + "110:0 -> 110:0", + "2:4 -> 112:0", + "113:2-14 -> 113:2-14", + "114:0 -> 114:0", + "2:4 -> 116:0", + "117:2-31 -> 117:2-31", + "118:2-22 -> 118:2-22", + "119:0 -> 119:0", + "2:4 -> 121:0", + "122:2-26 -> 122:2-26", + "123:0 -> 123:0", + "2:4 -> 125:0", + "126:2-28 -> 126:2-28", + "127:2-15 -> 127:2-15", + "128:0 -> 128:0", + "2:4 -> 130:0", + "131:2-20 -> 131:2-20", + "132:0 -> 132:0", + "2:4 -> 134:0", + "135:2-11 -> 135:2-11", + "136:0 -> 136:0", + "2:4 -> 138:0", + "139:2-11 -> 139:2-11", + "140:2-12 -> 140:2-12", + "141:0 -> 141:0", + "2:4 -> 143:0", + "144:2-12 -> 144:2-12", + "145:0 -> 145:0", + "2:4 -> 147:0", + "148:2-11 -> 148:2-11", + "149:2-12 -> 149:2-12", + "150:2-18 -> 150:2-18", + "151:0 -> 151:0", + "2:4 -> 153:0", + "154:2-12 -> 154:2-12", + "155:0 -> 155:0", + "2:4 -> 157:0", + "158:2-18 -> 158:2-18", + "159:0 -> 159:0", + "2:4 -> 161:0", + "162:2-12 -> 162:2-12", + "163:2-16 -> 163:2-16", + "164:0 -> 164:0", + "2:4 -> 166:0", + "167:2-17 -> 167:2-17", + "168:0 -> 168:0", + "2:4 -> 170:0", + "171:2-17 -> 171:2-17", + "172:0 -> 172:0", + "2:4 -> 174:0", + "175:2-24 -> 175:2-24", + "176:2-16 -> 176:2-16", + "177:0 -> 177:0", + "2:4 -> 179:0", + "180:2-17 -> 180:2-17", + "181:2-14 -> 181:2-14", + "182:0 -> 182:0", + "2:4 -> 184:0", + "185:2-15 -> 185:2-15", + "186:0 -> 186:0", + "2:4 -> 188:0", + "189:2-26 -> 189:2-26", + "190:2-26 -> 190:2-26", + "191:2-21 -> 191:2-21", + "192:2-21 -> 192:2-21", + "193:2-16 -> 193:2-16", + "194:2-16 -> 194:2-16", + "195:2-16 -> 195:2-16", + "196:2-17 -> 196:2-17", + "197:2-17 -> 197:2-17", + "198:2-14 -> 198:2-14", + "199:2-14 -> 199:2-14", + "200:2-19 -> 200:2-19", + "201:2-40 -> 201:2-40", + "202:2-31 -> 202:2-31", + "203:2-30 -> 203:2-30", + "204:2-29 -> 204:2-29", + "205:2-16 -> 205:2-16", + "206:2-21 -> 206:2-21", + "207:2-23 -> 207:2-23", + "208:2-24 -> 208:2-24", + "209:2-25 -> 209:2-25", + "210:2-19 -> 210:2-19", + "211:2-29 -> 211:2-29", + "212:2-30 -> 212:2-30", + "213:2-28 -> 213:2-28", + "214:2-36 -> 214:2-36", + "215:2-29 -> 215:2-29", + "216:2-24 -> 216:2-24", + "217:2-32 -> 217:2-32", + "218:2-13 -> 218:2-13", + "219:2-19 -> 219:2-19", + "220:2-17 -> 220:2-17", + "221:2-18 -> 221:2-18", + "222:2-19 -> 222:2-19", + "223:2-15 -> 223:2-15", + "224:2-17 -> 224:2-17", + "225:2-14 -> 225:2-14", + "226:2-20 -> 226:2-20", + "227:2-22 -> 227:2-22", + "228:2-28 -> 228:2-28", + "229:2-26 -> 229:2-26", + "230:2-27 -> 230:2-27", + "231:2-28 -> 231:2-28", + "232:2-24 -> 232:2-24", + "233:2-25 -> 233:2-25", + "234:2-26 -> 234:2-26", + "235:2-23 -> 235:2-23", + "236:0 -> 236:0", + ] + `) }) -test.skip('utilities have source maps', async () => { +test('utilities have source maps', async () => { let config = { content: [{ raw: `text-red-500` }], } @@ -412,12 +301,19 @@ test.skip('utilities have source maps', async () => { // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') - expect(sources.length).toBe(1) + expect(sources.length).toBe(2) - expect(annotations).toStrictEqual(['2:6 -> 1:0', '2:6-25 -> 2:4-24', '2:6 -> 3:4', '2:25 -> 4:0']) + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-22 -> 2:2-22", + "3:2-48 -> 3:2-48", + "4:0 -> 4:0", + ] + `) }) -test.skip('components have source maps', async () => { +test('components have source maps', async () => { let config = { content: [{ raw: `container` }], } @@ -432,41 +328,43 @@ test.skip('components have source maps', async () => { // All CSS generated by Tailwind CSS should be annotated with source maps // And always be able to point to the original source file expect(sources).not.toContain('') - expect(sources.length).toBe(1) + expect(sources.length).toBe(2) - expect(annotations).toEqual([ - '2:6 -> 1:0', - '2:6 -> 2:4', - '2:26 -> 3:0', - '2:6 -> 4:0', - '2:6 -> 5:4', - '2:6 -> 6:8', - '2:26 -> 7:4', - '2:26 -> 8:0', - '2:6 -> 9:0', - '2:6 -> 10:4', - '2:6 -> 11:8', - '2:26 -> 12:4', - '2:26 -> 13:0', - '2:6 -> 14:0', - '2:6 -> 15:4', - '2:6 -> 16:8', - '2:26 -> 17:4', - '2:26 -> 18:0', - '2:6 -> 19:0', - '2:6 -> 20:4', - '2:6 -> 21:8', - '2:26 -> 22:4', - '2:26 -> 23:0', - '2:6 -> 24:0', - '2:6 -> 25:4', - '2:6 -> 26:8', - '2:26 -> 27:4', - '2:26 -> 28:0', - ]) + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-13 -> 2:2-13", + "3:0 -> 3:0", + "2:4 -> 5:0", + "2:4 -> 6:2", + "7:4-20 -> 7:4-20", + "8:2 -> 8:2", + "9:0 -> 9:0", + "2:4 -> 11:0", + "2:4 -> 12:2", + "13:4-20 -> 13:4-20", + "14:2 -> 14:2", + "15:0 -> 15:0", + "2:4 -> 17:0", + "2:4 -> 18:2", + "19:4-21 -> 19:4-21", + "20:2 -> 20:2", + "21:0 -> 21:0", + "2:4 -> 23:0", + "2:4 -> 24:2", + "25:4-21 -> 25:4-21", + "26:2 -> 26:2", + "27:0 -> 27:0", + "2:4 -> 29:0", + "2:4 -> 30:2", + "31:4-21 -> 31:4-21", + "32:2 -> 32:2", + "33:0 -> 33:0", + ] + `) }) -test.skip('source maps for layer rules are not rewritten to point to @tailwind directives', async () => { +test('source maps for layer rules are not rewritten to point to @tailwind directives', async () => { let config = { content: [{ raw: `font-normal foo hover:foo` }], } @@ -505,18 +403,83 @@ test.skip('source maps for layer rules are not rewritten to point to @tailwind d // And we should see that the source map for the layer rule is not rewritten // to point to the @tailwind directive but instead points to the original - expect(sources.length).toBe(2) - expect(sources).toEqual(['components.css', 'input.css']) + expect(sources.length).toBe(3) + expect(sources).toMatchInlineSnapshot(` + [ + "components.css", + "source-maps.test.js%3Ftest=c291cmNlIG1hcHMgZm9yIGxheWVyIHJ1bGVzIGFyZSBub3QgcmV3cml0dGVuIHRvIHBvaW50IHRvIEB0YWlsd2luZCBkaXJlY3RpdmVz", + "input.css", + ] + `) - expect(annotations).toEqual([ - '2:10 -> 1:0', - '2:10 -> 2:14', - '2:29 -> 3:0', - '3:12 -> 4:12', - '4:14-35 -> 5:14-35', - '5:12 -> 6:12', - '3:12 -> 7:12', - '4:14-35 -> 8:14-35', - '5:12 -> 9:12', - ]) + expect(annotations).toMatchInlineSnapshot(` + [ + "2:6 -> 1:0", + "2:2-18 -> 2:2-18", + "3:0 -> 3:0", + "3:8 -> 5:0", + "6:2-23 -> 6:2-23", + "7:0 -> 7:0", + ] + `) +}) + +test('it handles `map: true` correctly', async () => { + let config = { + content: [{ raw: `text-red-500` }], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config, { + map: true, + }) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-22 -> 2:2-22", + "3:2-48 -> 3:2-48", + "4:0 -> 4:0", + ] + `) +}) + +test('it handles `map: { inline: true }` correctly', async () => { + let config = { + content: [{ raw: `text-red-500` }], + } + + let input = css` + @tailwind utilities; + ` + + let result = await run(input, config, { + map: { + inline: true, + }, + }) + let { sources, annotations } = parseSourceMaps(result) + + // All CSS generated by Tailwind CSS should be annotated with source maps + // And always be able to point to the original source file + expect(sources).not.toContain('') + expect(sources.length).toBe(2) + + expect(annotations).toMatchInlineSnapshot(` + [ + "2:4 -> 1:0", + "2:2-22 -> 2:2-22", + "3:2-48 -> 3:2-48", + "4:0 -> 4:0", + ] + `) }) diff --git a/tests/util/run.js b/tests/util/run.js index 08dbc3b80..12594ec18 100644 --- a/tests/util/run.js +++ b/tests/util/run.js @@ -1,4 +1,3 @@ -import path from 'path' import postcss from 'postcss' import tailwind from '../../src' @@ -15,19 +14,26 @@ export let map = JSON.stringify({ export function run(input, config, plugin = tailwind) { let { currentTestName, testPath } = expect.getState() + let path = `${testPath}?test=${Buffer.from(currentTestName).toString('base64')}` return postcss(plugin(config)).process(input, { - from: `${path.resolve(testPath)}?test=${currentTestName}`, + from: path, + to: path, }) } -export function runWithSourceMaps(input, config, plugin = tailwind) { +export function runWithSourceMaps( + input, + config, + options = { map: { prev: map } }, + plugin = tailwind +) { let { currentTestName, testPath } = expect.getState() + let path = `${testPath}?test=${Buffer.from(currentTestName).toString('base64')}` return postcss(plugin(config)).process(input, { - from: `${path.resolve(testPath)}?test=${currentTestName}`, - map: { - prev: map, - }, + from: path, + to: path, + ...options, }) } diff --git a/tests/util/source-maps.js b/tests/util/source-maps.js index 4ed263126..fe460d844 100644 --- a/tests/util/source-maps.js +++ b/tests/util/source-maps.js @@ -6,7 +6,16 @@ import { SourceMapConsumer } from 'source-map-js' * @param {import('postcss').Result} result */ export function parseSourceMaps(result) { - let map = result.map.toJSON() + let map = result.map + ? result.map.toJSON() + : (() => { + let css = result.toString() + let sourceMappingURL = css.match(/\/\*# sourceMappingURL=(.*) \*\//)?.[1] + let raw = sourceMappingURL + ? Buffer.from(sourceMappingURL.split(',')[1], 'base64').toString() + : null + return JSON.parse(raw ?? '{}') + })() return { sources: map.sources, @@ -15,7 +24,7 @@ export function parseSourceMaps(result) { } /** - * An string annotation that represents a source map + * A string annotation that represents a source map * * It's not meant to be exhaustive just enough to * verify that the source map is working and that From 5c7a8e98ea8b00b1bd0b081ff0ce8e352a5d8341 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 1 Jun 2023 13:24:53 +0200 Subject: [PATCH 43/85] use `parseCandidateStrings` directly (#11332) + drop the `parseCandidateStringsFromFiles` since this can be implemented using `parseCandidateStrings` already. --- oxide/crates/core/Cargo.toml | 2 +- ...rings_from_files.rs => parse_candidate_strings.rs} | 11 ++++++++--- oxide/crates/core/src/lib.rs | 5 ----- oxide/crates/node/src/lib.rs | 7 ------- src/lib/expandTailwindAtRules.js | 7 ++++--- 5 files changed, 13 insertions(+), 19 deletions(-) rename oxide/crates/core/benches/{parse_candidate_strings_from_files.rs => parse_candidate_strings.rs} (85%) diff --git a/oxide/crates/core/Cargo.toml b/oxide/crates/core/Cargo.toml index 0db8eb2b2..3b0b3d123 100644 --- a/oxide/crates/core/Cargo.toml +++ b/oxide/crates/core/Cargo.toml @@ -24,5 +24,5 @@ name = "parse_candidates" harness = false [[bench]] -name = "parse_candidate_strings_from_files" +name = "parse_candidate_strings" harness = false diff --git a/oxide/crates/core/benches/parse_candidate_strings_from_files.rs b/oxide/crates/core/benches/parse_candidate_strings.rs similarity index 85% rename from oxide/crates/core/benches/parse_candidate_strings_from_files.rs rename to oxide/crates/core/benches/parse_candidate_strings.rs index a9e5faf9d..7db451000 100644 --- a/oxide/crates/core/benches/parse_candidate_strings_from_files.rs +++ b/oxide/crates/core/benches/parse_candidate_strings.rs @@ -1,6 +1,6 @@ use criterion::{criterion_group, criterion_main, Criterion}; use std::path::PathBuf; -use tailwindcss_core::{parse_candidate_strings_from_files, ChangedContent}; +use tailwindcss_core::{parse_candidate_strings, ChangedContent, Parsing, IO}; pub fn criterion_benchmark(c: &mut Criterion) { // current_dir will be set to ./crates/core @@ -51,8 +51,13 @@ pub fn criterion_benchmark(c: &mut Criterion) { }) .collect(); - c.bench_function("parse_candidate_strings_from_files", |b| { - b.iter(|| parse_candidate_strings_from_files(changed_content.clone())) + c.bench_function("parse_candidate_strings", |b| { + b.iter(|| { + parse_candidate_strings( + changed_content.clone(), + Parsing::Parallel as u8 | IO::Parallel as u8, + ) + }) }); } diff --git a/oxide/crates/core/src/lib.rs b/oxide/crates/core/src/lib.rs index 6601267fd..6d6202895 100644 --- a/oxide/crates/core/src/lib.rs +++ b/oxide/crates/core/src/lib.rs @@ -335,11 +335,6 @@ impl From for Parsing { } } -pub fn parse_candidate_strings_from_files(changed_content: Vec) -> Vec { - init_tracing(); - parse_all_blobs(read_all_files(changed_content)) -} - pub fn parse_candidate_strings(input: Vec, options: u8) -> Vec { init_tracing(); diff --git a/oxide/crates/node/src/lib.rs b/oxide/crates/node/src/lib.rs index 343a6e367..f974de1d5 100644 --- a/oxide/crates/node/src/lib.rs +++ b/oxide/crates/node/src/lib.rs @@ -22,13 +22,6 @@ impl From for tailwindcss_core::ChangedContent { } } -#[napi] -pub fn parse_candidate_strings_from_files(changed_content: Vec) -> Vec { - tailwindcss_core::parse_candidate_strings_from_files( - changed_content.into_iter().map(Into::into).collect(), - ) -} - #[derive(Debug, Clone)] #[napi(object)] pub struct ContentPathInfo { diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index 34257e148..e93740a96 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -1,6 +1,6 @@ import fs from 'fs' import LRU from '@alloc/quick-lru' -import { parseCandidateStringsFromFiles } from '@tailwindcss/oxide' +import { parseCandidateStrings, IO, Parsing } from '@tailwindcss/oxide' import * as sharedState from './sharedState' import { generateRules } from './generateRules' import log from '../util/log' @@ -134,8 +134,9 @@ export default function expandTailwindAtRules(context) { if (flagEnabled(context.tailwindConfig, 'oxideParser')) { // TODO: Pass through or implement `extractor` - for (let candidate of parseCandidateStringsFromFiles( - context.changedContent + for (let candidate of parseCandidateStrings( + context.changedContent, + IO.Parallel | Parsing.Parallel // Object.assign({}, builtInTransformers, context.tailwindConfig.content.transform) )) { candidates.add(candidate) From 5ddd9c4db62244204eab93860394021414b0300d Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 1 Jun 2023 22:37:12 +0200 Subject: [PATCH 44/85] Fallback to RegEx based parser when using custom transformers or extractors (#11335) * handle custom `transformer` and `extractor` implementations Right now the Rust based parser can't work with custom `transfomers` or `extractors`. In a perfect world we can implement as many custom parsers/extractors in Rust such that we don't need this at all. In an almost perfect world we can pass the transformer and extractor to the Rust based parser and call the callback functions to handle all of this. This is probably what we are going to do in the future but this requires more work to make sure that: 1. It works as expected 2. Doesn't result in (major) performance issues Since it currently doesn't work with the Rust based parser, we can implement a fix for this in the meantime before we reach the "perfect" solution. One solution to this problem is to check if we do have a custom transformer or a custom extractor and if we do, then we can bail on the Rust parser completely and just use the current regex based parser. An alternative solution, the solution implemented here, is that we group the `changedContent` into 2 buckets. The bucket where we rely on the default transformer and extractor and a bucket where a custom transformer or extractor is used. Then, the bucket where we use the default transformer and extractor can still rely on the way faster Rust based parser. For the other bucket we fallback to the regex based parser. The nice part about this is that we can use both parsers at the same time, and the majority of the use cases should use the faster Rust based parser. * update changelog --- CHANGELOG.md | 1 + src/lib/expandTailwindAtRules.js | 63 +++++++++++++++++++++----------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46498cc9f..e0ed544b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) - Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) - Fix source maps issue resulting in a crash ([#11319](https://github.com/tailwindlabs/tailwindcss/pull/11319)) +- Fallback to RegEx based parser when using custom transformers or extractors ([#11335](https://github.com/tailwindlabs/tailwindcss/pull/11335)) ### Added diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index e93740a96..5f4391a15 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -26,7 +26,10 @@ function getExtractor(context, fileExtension) { extractors[fileExtension] || extractors.DEFAULT || builtInExtractors[fileExtension] || - builtInExtractors.DEFAULT(context) + // Because we call `DEFAULT(context)`, the returning function is always a new function without a + // stable identity. Marking it with `DEFAULT_EXTRACTOR` allows us to check if it is the default + // extractor without relying on the function identity. + Object.assign(builtInExtractors.DEFAULT(context), { DEFAULT_EXTRACTOR: true }) ) } @@ -133,20 +136,35 @@ export default function expandTailwindAtRules(context) { env.DEBUG && console.time('Reading changed files') if (flagEnabled(context.tailwindConfig, 'oxideParser')) { - // TODO: Pass through or implement `extractor` - for (let candidate of parseCandidateStrings( - context.changedContent, - IO.Parallel | Parsing.Parallel - // Object.assign({}, builtInTransformers, context.tailwindConfig.content.transform) - )) { - candidates.add(candidate) + let rustParserContent = [] + let regexParserContent = [] + + for (let item of context.changedContent) { + let transformer = getTransformer(context.tailwindConfig, item.extension) + let extractor = getExtractor(context, item.extension) + + if (transformer === builtInTransformers.DEFAULT && extractor?.DEFAULT_EXTRACTOR === true) { + rustParserContent.push(item) + } else { + regexParserContent.push([item, { transformer, extractor }]) + } } - // for (let { file, content, extension } of context.changedContent) { - // let transformer = getTransformer(context.tailwindConfig, extension) - // let extractor = getExtractor(context, extension) - // getClassCandidatesOxide(file, transformer(content), extractor, candidates, seen) - // } + if (rustParserContent.length > 0) { + for (let candidate of parseCandidateStrings( + rustParserContent, + IO.Parallel | Parsing.Parallel + )) { + candidates.add(candidate) + } + } + + if (regexParserContent.length > 0) { + for (let [{ file, content }, { transformer, extractor }] of regexParserContent) { + content = file ? fs.readFileSync(file, 'utf8') : content + getClassCandidates(transformer(content), extractor, candidates, seen) + } + } } else { for (let { file, content, extension } of context.changedContent) { let transformer = getTransformer(context.tailwindConfig, extension) @@ -165,15 +183,16 @@ export default function expandTailwindAtRules(context) { env.DEBUG && console.time('Generate rules') env.DEBUG && console.time('Sorting candidates') - let sortedCandidates = flagEnabled(context.tailwindConfig, 'oxideParser') - ? candidates - : new Set( - [...candidates].sort((a, z) => { - if (a === z) return 0 - if (a < z) return -1 - return 1 - }) - ) + // TODO: only sort if we are not using the oxide parser (flagEnabled(context.tailwindConfig, + // 'oxideParser')) AND if we got all the candidates form the oxideParser alone. This will not + // be the case currently if you have custom transformers / extractors. + let sortedCandidates = new Set( + [...candidates].sort((a, z) => { + if (a === z) return 0 + if (a < z) return -1 + return 1 + }) + ) env.DEBUG && console.timeEnd('Sorting candidates') generateRules(sortedCandidates, context) env.DEBUG && console.timeEnd('Generate rules') From 9794b83985f02a2bea2ac558a7ac7c6b3da218ed Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 08:41:51 +0000 Subject: [PATCH 45/85] Update parcel to version 2.9.1 --- integrations/parcel/package.json | 2 +- package-lock.json | 4099 +++++++++++------------------- 2 files changed, 1453 insertions(+), 2648 deletions(-) diff --git a/integrations/parcel/package.json b/integrations/parcel/package.json index c61b3df00..6818c078f 100644 --- a/integrations/parcel/package.json +++ b/integrations/parcel/package.json @@ -19,6 +19,6 @@ } }, "devDependencies": { - "parcel": "^2.8.3" + "parcel": "^2.9.1" } } diff --git a/package-lock.json b/package-lock.json index 4a5c885f3..0a07642b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -76,7 +76,7 @@ "name": "@tailwindcss/integrations-parcel", "version": "0.0.0", "devDependencies": { - "parcel": "^2.8.3" + "parcel": "2.9.1" } }, "integrations/postcss-cli": { @@ -2308,9 +2308,9 @@ } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", - "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", "cpu": [ "arm64" ], @@ -2321,9 +2321,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", "cpu": [ "x64" ], @@ -2334,9 +2334,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", "cpu": [ "arm" ], @@ -2347,9 +2347,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", "cpu": [ "arm64" ], @@ -2360,9 +2360,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", "cpu": [ "x64" ], @@ -2373,9 +2373,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", "cpu": [ "x64" ], @@ -2419,9 +2419,9 @@ } }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", - "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", "cpu": [ "arm64" ], @@ -2432,9 +2432,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", - "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", "cpu": [ "x64" ], @@ -2445,9 +2445,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", - "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", "cpu": [ "arm" ], @@ -2458,9 +2458,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", - "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", "cpu": [ "arm64" ], @@ -2471,9 +2471,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", - "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", "cpu": [ "x64" ], @@ -2484,9 +2484,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", - "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", "cpu": [ "x64" ], @@ -2542,21 +2542,21 @@ } }, "node_modules/@parcel/bundler-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.8.3.tgz", - "integrity": "sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.1.tgz", + "integrity": "sha512-gNTaSQpp7jiFvkQ/P/KfAiVLT3UOEs5bBivQm4OMdgSi2DTIsjGMQVQ7JDzvzEzrHiFlDmdXKxUagex54pOtJg==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2564,15 +2564,15 @@ } }, "node_modules/@parcel/cache": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.3.tgz", - "integrity": "sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.1.tgz", + "integrity": "sha512-2aFWUAi7vkcnIdfOw3oW/vhgvwv9MPb+LjmJSkE59nNUuSJe83jJFAPAhqQTHd9L3kX/Xk+xJBNYNubUq/Cieg==", "dev": true, "dependencies": { - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/utils": "2.8.3", - "lmdb": "2.5.2" + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/utils": "2.9.1", + "lmdb": "2.7.11" }, "engines": { "node": ">= 12.0.0" @@ -2582,13 +2582,13 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/codeframe": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", - "integrity": "sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.1.tgz", + "integrity": "sha512-qLVIyEHuZq8wWYaXVAwxMzlK3QqWlaB5fUSe1n+kITEa9EEwb2WPmysYAsWiVaFdD62A0+1klJ8Sq9gapOMIng==", "dev": true, "dependencies": { "chalk": "^4.1.0" @@ -2602,16 +2602,16 @@ } }, "node_modules/@parcel/compressor-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz", - "integrity": "sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.1.tgz", + "integrity": "sha512-aUkZ0pOzGjQ9kyaUQ/suDVmU5lR4mT9fU5HXlp3hGD7MWh2HFJUOfQ3gp5g3P9x+MeVZKU+ht6UcIMhrzelLGQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2619,70 +2619,71 @@ } }, "node_modules/@parcel/config-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.8.3.tgz", - "integrity": "sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.1.tgz", + "integrity": "sha512-oH6NHKaKp2YBHOcQJxwHGPbgGCZZZH1I4eef+KRBFiabgiDQxHLni+vg+c+mErd8lFrNn2gcGIdKzQwWqavT+w==", "dev": true, "dependencies": { - "@parcel/bundler-default": "2.8.3", - "@parcel/compressor-raw": "2.8.3", - "@parcel/namer-default": "2.8.3", - "@parcel/optimizer-css": "2.8.3", - "@parcel/optimizer-htmlnano": "2.8.3", - "@parcel/optimizer-image": "2.8.3", - "@parcel/optimizer-svgo": "2.8.3", - "@parcel/optimizer-terser": "2.8.3", - "@parcel/packager-css": "2.8.3", - "@parcel/packager-html": "2.8.3", - "@parcel/packager-js": "2.8.3", - "@parcel/packager-raw": "2.8.3", - "@parcel/packager-svg": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/resolver-default": "2.8.3", - "@parcel/runtime-browser-hmr": "2.8.3", - "@parcel/runtime-js": "2.8.3", - "@parcel/runtime-react-refresh": "2.8.3", - "@parcel/runtime-service-worker": "2.8.3", - "@parcel/transformer-babel": "2.8.3", - "@parcel/transformer-css": "2.8.3", - "@parcel/transformer-html": "2.8.3", - "@parcel/transformer-image": "2.8.3", - "@parcel/transformer-js": "2.8.3", - "@parcel/transformer-json": "2.8.3", - "@parcel/transformer-postcss": "2.8.3", - "@parcel/transformer-posthtml": "2.8.3", - "@parcel/transformer-raw": "2.8.3", - "@parcel/transformer-react-refresh-wrap": "2.8.3", - "@parcel/transformer-svg": "2.8.3" + "@parcel/bundler-default": "2.9.1", + "@parcel/compressor-raw": "2.9.1", + "@parcel/namer-default": "2.9.1", + "@parcel/optimizer-css": "2.9.1", + "@parcel/optimizer-htmlnano": "2.9.1", + "@parcel/optimizer-image": "2.9.1", + "@parcel/optimizer-svgo": "2.9.1", + "@parcel/optimizer-swc": "2.9.1", + "@parcel/packager-css": "2.9.1", + "@parcel/packager-html": "2.9.1", + "@parcel/packager-js": "2.9.1", + "@parcel/packager-raw": "2.9.1", + "@parcel/packager-svg": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/resolver-default": "2.9.1", + "@parcel/runtime-browser-hmr": "2.9.1", + "@parcel/runtime-js": "2.9.1", + "@parcel/runtime-react-refresh": "2.9.1", + "@parcel/runtime-service-worker": "2.9.1", + "@parcel/transformer-babel": "2.9.1", + "@parcel/transformer-css": "2.9.1", + "@parcel/transformer-html": "2.9.1", + "@parcel/transformer-image": "2.9.1", + "@parcel/transformer-js": "2.9.1", + "@parcel/transformer-json": "2.9.1", + "@parcel/transformer-postcss": "2.9.1", + "@parcel/transformer-posthtml": "2.9.1", + "@parcel/transformer-raw": "2.9.1", + "@parcel/transformer-react-refresh-wrap": "2.9.1", + "@parcel/transformer-svg": "2.9.1" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.3.tgz", - "integrity": "sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.1.tgz", + "integrity": "sha512-D/7iyRV5c8kYMV1JGkokktxh3ON5CMvNAllaBucl4SMatAyLo5aLjGG5ey6FD/4Tv+JJ6NsldLtkvciDVJdgFQ==", "dev": true, "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/profiler": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", @@ -2712,9 +2713,9 @@ } }, "node_modules/@parcel/diagnostic": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.3.tgz", - "integrity": "sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.1.tgz", + "integrity": "sha512-LM+w4maoAsjcL+javaHw9B9oEQoLdg/fMCNbuTmAKpQWi16hfNkr4+xz7AxxwL3dCcL7uuvVgoUOUubwxWNLAA==", "dev": true, "dependencies": { "@mischnic/json-sourcemap": "^0.1.0", @@ -2729,9 +2730,9 @@ } }, "node_modules/@parcel/events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.3.tgz", - "integrity": "sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.1.tgz", + "integrity": "sha512-tga4FiJB1TC4iOKBK66e9zXpcDFXvJhXmsgOMsgSTM6uCZMXeGaYEixHNlPDs3HTfg17qAmHHlhfgPBbku/aOg==", "dev": true, "engines": { "node": ">= 12.0.0" @@ -2742,16 +2743,16 @@ } }, "node_modules/@parcel/fs": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.3.tgz", - "integrity": "sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.1.tgz", + "integrity": "sha512-F/GRHtHN4AuTauadsq/UQ1OSpLBLAS/96Sv1x09/AKZxNlZ2UzWExoYEhSkVM5smKVzSnx8XP9OqABcHcZwOLQ==", "dev": true, "dependencies": { - "@parcel/fs-search": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/fs-search": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "@parcel/watcher": "^2.0.7", - "@parcel/workers": "2.8.3" + "@parcel/workers": "2.9.1" }, "engines": { "node": ">= 12.0.0" @@ -2761,17 +2762,14 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/fs-search": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.3.tgz", - "integrity": "sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.1.tgz", + "integrity": "sha512-F7SkVsMb5XYcWmeptLz5D3g76Raed3dmNulJMrWIECP8lJ1LUcCExQId7NsdeCfRbNRwaf84gdsjc/1GKM/QYg==", "dev": true, - "dependencies": { - "detect-libc": "^1.0.3" - }, "engines": { "node": ">= 12.0.0" }, @@ -2781,9 +2779,9 @@ } }, "node_modules/@parcel/graph": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.3.tgz", - "integrity": "sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.1.tgz", + "integrity": "sha512-fc/Yk1XPzo3ZHhKS7l5aETAEBpnF0nK+0TawkNrQ2rcL21MG1kHNYSR8uBwOqyXmBSMEItals5Ixgd8fWa+9PQ==", "dev": true, "dependencies": { "nullthrows": "^1.1.1" @@ -2797,12 +2795,11 @@ } }, "node_modules/@parcel/hash": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.3.tgz", - "integrity": "sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.1.tgz", + "integrity": "sha512-fiqAIi/23h5tnH5W7DRTwOhfRPhadHvI7hYoG8YFGvnFxSQ/XCnOID0B0/vNhaluICSPeFcedjAmDVdqY6/X7w==", "dev": true, "dependencies": { - "detect-libc": "^1.0.3", "xxhash-wasm": "^0.4.2" }, "engines": { @@ -2814,13 +2811,13 @@ } }, "node_modules/@parcel/logger": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.3.tgz", - "integrity": "sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.1.tgz", + "integrity": "sha512-wUH9ShrRr3RwNa75ymegDIAdJiY3dGB7HCgIP6VOOc2CGyGA2DJKbbYGfw5mkl3DV8lUV+dYsWYMGXZhInAQCQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1" }, "engines": { "node": ">= 12.0.0" @@ -2831,9 +2828,9 @@ } }, "node_modules/@parcel/markdown-ansi": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz", - "integrity": "sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.1.tgz", + "integrity": "sha512-FpOz2ltnKnm6QaQCdcpuAEwGuScVUq0ixT/QAmU7A3/cwlsoxqMkB2XeWYIVTjs7p7Bsu0Ctdid/6pdtP7ghpg==", "dev": true, "dependencies": { "chalk": "^4.1.0" @@ -2847,18 +2844,18 @@ } }, "node_modules/@parcel/namer-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.8.3.tgz", - "integrity": "sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.1.tgz", + "integrity": "sha512-XHpAc5JLQchUqRrYqnUvinReR2nCyiD+DhIedMW5hURwlCPBlfcTVf6M5kSSpjzqRDVKezx3TFF6dzZNv0fBJQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2866,13 +2863,15 @@ } }, "node_modules/@parcel/node-resolver-core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz", - "integrity": "sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.1.tgz", + "integrity": "sha512-4owokOoHCONeazQGndB4PkIaUhZfyWuCT7Sx4UJc2UhR1V82MlahHrT2ItT0pkQyKWwCSNgHdBgdKUgKRdIiAw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/utils": "2.8.3", + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "semver": "^5.7.1" }, @@ -2894,22 +2893,22 @@ } }, "node_modules/@parcel/optimizer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz", - "integrity": "sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.1.tgz", + "integrity": "sha512-IYQpV0kc0KN/aqRAWQsZ8b2pbI4ha4T5HAi27lTGIhQNvEixUtf0gJvCJVSlBxpdMiXVJq9pp97UamoNuB6oig==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -2917,12 +2916,12 @@ } }, "node_modules/@parcel/optimizer-htmlnano": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz", - "integrity": "sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.1.tgz", + "integrity": "sha512-t/e9XsoXZViqOFWcz3LlEClCOYNCjP6MIo+p+WmAuc5+QFF0/9viNqgRbhVe8V1tbtRofxsm4BossFOjOBSjmg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", @@ -2930,7 +2929,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3006,20 +3005,19 @@ } }, "node_modules/@parcel/optimizer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz", - "integrity": "sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.1.tgz", + "integrity": "sha512-Ml51RUGbQXyoHZ9yhyal8J/khZeWZX5J8NPOEvkCmmOkxo/qM4CMPIvJStzzn5K7mOPRKUheDkM/QoNGO5gTwA==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "detect-libc": "^1.0.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3027,19 +3025,19 @@ } }, "node_modules/@parcel/optimizer-svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz", - "integrity": "sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.1.tgz", + "integrity": "sha512-8XHSEIjJfdTFtUQzRiy0K+fbvdcheYc+azdyuJPnIV5AX04k4heKwp7uH328Ylk2k0JkfDyQmjFEyPj9qWDadQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "svgo": "^2.4.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3114,22 +3112,22 @@ "node": ">=10.13.0" } }, - "node_modules/@parcel/optimizer-terser": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz", - "integrity": "sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==", + "node_modules/@parcel/optimizer-swc": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.1.tgz", + "integrity": "sha512-bLDkAwkmFE8YZNHcfJNj22haSLXrqjZkGXbPgGDkanCUS52yWv1+OFZ+6frX2q4EdXaTX8nFZSJL4VPHZZiUGQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "nullthrows": "^1.1.1", - "terser": "^5.2.0" + "@parcel/utils": "2.9.1", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3137,17 +3135,18 @@ } }, "node_modules/@parcel/package-manager": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.3.tgz", - "integrity": "sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.1.tgz", + "integrity": "sha512-cTUBUPRm62770Vw4YG5WGlkFxJII320nSobbP0TMggE/CGXg3ru2pvvX6WqXTFAHeM/z78xTPDq0NP97DBp5Ow==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/node-resolver-core": "3.0.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "semver": "^5.7.1" }, "engines": { @@ -3158,7 +3157,7 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/package-manager/node_modules/semver": { @@ -3171,19 +3170,20 @@ } }, "node_modules/@parcel/packager-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.8.3.tgz", - "integrity": "sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.1.tgz", + "integrity": "sha512-efMShrIwVBY9twZTGQ5QFwl9H3xJg8nSjl/xgOGq9rrbkmcrVlfSgPL9ExNx75EvmOwOKxZjFiMsNYNICPNfgg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3191,20 +3191,20 @@ } }, "node_modules/@parcel/packager-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.8.3.tgz", - "integrity": "sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.1.tgz", + "integrity": "sha512-mP7iIwyFDZ21XwD2SlwZoSrvKpS5Amlpi/ywd0dLdwQb5TL+Q2f05IcRNfFbWdVd1AJycDQ85ERokNKN3QPMkg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3212,22 +3212,22 @@ } }, "node_modules/@parcel/packager-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.8.3.tgz", - "integrity": "sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.1.tgz", + "integrity": "sha512-MmeKdp/obO36M8Y9yYAFiFkdhRFbQtYGSxbMwm2JVtRKMcFmlR5KzqLUg67OX6qgKw5lZZ1TkYhSI0hQQ6+Vqw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "globals": "^13.2.0", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3235,9 +3235,9 @@ } }, "node_modules/@parcel/packager-js/node_modules/globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3250,16 +3250,16 @@ } }, "node_modules/@parcel/packager-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.8.3.tgz", - "integrity": "sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.1.tgz", + "integrity": "sha512-qHJ389R5cLgR2PcJt8sOrNBcAY0qpZRMTOMgkc9zYkKy1tdUMgCUuDfO1kShfv4E7rr084mtlu9tK8MXChyF6w==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3267,19 +3267,19 @@ } }, "node_modules/@parcel/packager-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.8.3.tgz", - "integrity": "sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.1.tgz", + "integrity": "sha512-aRzuiwcUlNATfSIbeYpDkJXvwdiAAbiQlxSz6cI53NqWwZn+Dn79WyiKPBST14ij4/P3ZjkcwXevqHpvXP/ArQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "posthtml": "^0.16.4" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3287,12 +3287,30 @@ } }, "node_modules/@parcel/plugin": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.3.tgz", - "integrity": "sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.1.tgz", + "integrity": "sha512-kD+BNkPGRcxZZUKhAXqF/bilUMhXUlf/ZixVlBS5rEsUB1yx/Ze8c4ypaKr5WsEwv34C+X4p4WFYdZVJEr3Y+g==", "dev": true, "dependencies": { - "@parcel/types": "2.8.3" + "@parcel/types": "2.9.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/profiler": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.1.tgz", + "integrity": "sha512-hrptwbh9uUxnWHAAXiZ6BtpM74cU+VfrOWgnmUA8pkYWBmrb2wSLeqRKl8FiSt+nfRTTbNAIlmn9vk2x+wRNOA==", + "dev": true, + "dependencies": { + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "chrome-trace-event": "^1.0.2" }, "engines": { "node": ">= 12.0.0" @@ -3303,20 +3321,20 @@ } }, "node_modules/@parcel/reporter-cli": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz", - "integrity": "sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.9.1.tgz", + "integrity": "sha512-xzJaaHQwcsmHijlCl7gOAdqU0n6AnW7c7rN8AXDH8BvnOx2v8NC8nCIEmDTOfpQYepcuER2+ilTQ7jpDx/iDhg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "term-size": "^2.2.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3324,17 +3342,37 @@ } }, "node_modules/@parcel/reporter-dev-server": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz", - "integrity": "sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.1.tgz", + "integrity": "sha512-Wa9kmtnuYTqEsKakhrSLvZmWxM4TB+Dg2jl1vC3gYfvlsgt/d/Hp/y2giPH1EeCm4wEEQfdAY3WmSUx9p1x07w==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/reporter-tracer": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.9.1.tgz", + "integrity": "sha512-LgZKx9qwBAChWHBcpHW8GJXz45IGtiPmzs6HIDavZOiGqjGVzmbHUKxHnFaRZqR6WznJ+0ay/2o+BrJ8cyXUcg==", + "dev": true, + "dependencies": { + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">= 12.0.0", + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3342,17 +3380,17 @@ } }, "node_modules/@parcel/resolver-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.8.3.tgz", - "integrity": "sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.1.tgz", + "integrity": "sha512-Q+knNaRDTbGIGqUnddtWEgpYduVBkDyi/CpxKpi7dP7sVYNJsXwEf82hpjX6/XqotA5dehT63yJkvJ/wxJF1Nw==", "dev": true, "dependencies": { - "@parcel/node-resolver-core": "2.8.3", - "@parcel/plugin": "2.8.3" + "@parcel/node-resolver-core": "3.0.1", + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3360,17 +3398,17 @@ } }, "node_modules/@parcel/runtime-browser-hmr": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz", - "integrity": "sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.1.tgz", + "integrity": "sha512-C+023FOsrycpBHUgUf7Nv4uN0NrLN3UkeymsAHQlgZD5QQD7+nhG6p9PQ7+HbbEAaGaeO7c/86s2qRUglufNig==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3378,18 +3416,19 @@ } }, "node_modules/@parcel/runtime-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.8.3.tgz", - "integrity": "sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.1.tgz", + "integrity": "sha512-caT1s1BqYNFGFAz9ul7uwDf+ZXzipiYYoHphhmT2JFweQmRA1CrMeFCuCQa2exsdu+UQpRbuKd+v5UUS2n0poQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3397,19 +3436,19 @@ } }, "node_modules/@parcel/runtime-react-refresh": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz", - "integrity": "sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.1.tgz", + "integrity": "sha512-opDW9p3f4gVc1aVdFAyLWTL+2S8rhsPdBQRBHEi4WE2DRe/9lpA12NN5KUUHy88dlIr3wyzmaO2Fts0r/x80zg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-error-overlay": "6.0.9", "react-refresh": "^0.9.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3417,18 +3456,18 @@ } }, "node_modules/@parcel/runtime-service-worker": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz", - "integrity": "sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.1.tgz", + "integrity": "sha512-TED4MouYjP7xbU9V7/3rjnmuWbCefrP+OC+eQJG6j3HwKiL92QTZ6trWqdLuxFhtZMXKjwbWaBBbIcELB/PbtQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3448,15 +3487,15 @@ } }, "node_modules/@parcel/transformer-babel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz", - "integrity": "sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.1.tgz", + "integrity": "sha512-HEU3bavD9Cu0RP5T1ioGLbsOQDqND/SQWal8L2f9HsgwTs2kzmTxYylNccqNjAMj3NnoyXzKMKbZyG8qEuLlpw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -3464,7 +3503,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3481,22 +3520,22 @@ } }, "node_modules/@parcel/transformer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.8.3.tgz", - "integrity": "sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.1.tgz", + "integrity": "sha512-nT+xOfyveX6qSb088dOh59HWJ1gm7DAIQZPbjTa1wLzRQul8ysdQRf/loulBmtUheol7YwQtVvUHN2XgoMDCAw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3504,14 +3543,14 @@ } }, "node_modules/@parcel/transformer-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.8.3.tgz", - "integrity": "sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.1.tgz", + "integrity": "sha512-pIkJbcB91Dl2RyZmVd9neGkf7XJeYXwgx0et5hktw+3m0S2QB399OjVWwi5Q6ZdtTrWkQnHLmbeHT3NOmNWlaw==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -3521,7 +3560,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3538,61 +3577,51 @@ } }, "node_modules/@parcel/transformer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.8.3.tgz", - "integrity": "sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.1.tgz", + "integrity": "sha512-3D4zEavCM1i354ZgJWg7RBNgASA7Q2iHN374lH5hT6I7VAJzNT+PTNrPNQ4vKhi69r+i1sQQzsPdgEUXOExmbQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/transformer-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.8.3.tgz", - "integrity": "sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.1.tgz", + "integrity": "sha512-7hlbAIufIvx6iPspfZ3v1g2cmtpaNEaC04RzRv8HVVru8TE868yplFI840ZBnF5ylOfmxwFTUjlphVtVcPs13A==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "@swc/helpers": "^0.4.12", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", + "@swc/helpers": "^0.5.0", "browserslist": "^4.6.6", - "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", "regenerator-runtime": "^0.13.7", "semver": "^5.7.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" - } - }, - "node_modules/@parcel/transformer-js/node_modules/@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dev": true, - "dependencies": { - "tslib": "^2.4.0" + "@parcel/core": "^2.9.1" } }, "node_modules/@parcel/transformer-js/node_modules/semver": { @@ -3605,17 +3634,17 @@ } }, "node_modules/@parcel/transformer-json": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.8.3.tgz", - "integrity": "sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.1.tgz", + "integrity": "sha512-yFRSz1qVbdCssC65D37Ru3diQk7GQl5ZOOyQ7MeMYlhvl8mcFKGRC3wUAyqBZrh70VOWuWR7WS2XLdqTdE9WqQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "json5": "^2.2.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3623,15 +3652,15 @@ } }, "node_modules/@parcel/transformer-postcss": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz", - "integrity": "sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.1.tgz", + "integrity": "sha512-sNSJbdT4Z8H+/cZ/vCmos44SfbB9O5gNgMEgGa6WqU7MV7cVlnE8zuNJkxR97ZZTpIXNrfVerOY3lOrUrFCxdA==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "clone": "^2.1.1", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", @@ -3639,7 +3668,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3656,13 +3685,13 @@ } }, "node_modules/@parcel/transformer-posthtml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz", - "integrity": "sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.1.tgz", + "integrity": "sha512-I6fr6lVAqjDxdkOwxelx7FibMWP55JPf3ZTXKCWpoIGkOuT2i2tYZMdXEHVshZWJmByelbYSC96w8P8rSY+6XQ==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -3671,7 +3700,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3688,16 +3717,16 @@ } }, "node_modules/@parcel/transformer-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz", - "integrity": "sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.1.tgz", + "integrity": "sha512-Wr0Y9fETiyF5ntL3yhn/ZXjcnswcn1T9YLXa+yAxpAxKW+/D7A1jKVS0tyDOZsdakWA9gzlLP6w1O4Nl8pVmEg==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3705,18 +3734,18 @@ } }, "node_modules/@parcel/transformer-react-refresh-wrap": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz", - "integrity": "sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.1.tgz", + "integrity": "sha512-ML+KDvLoZ6O+9r3/yf8DeVtobhYc9DPXYHZ75aXoFyou97I9WDf4EqlY4/MSkbZV79FUXxC68dyLJj3Q9ILqeA==", "dev": true, "dependencies": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-refresh": "^0.9.0" }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3724,14 +3753,14 @@ } }, "node_modules/@parcel/transformer-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz", - "integrity": "sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.1.tgz", + "integrity": "sha512-DYcUfutjtghPXMVybFygncIKJl/4rrpQMxv8yTVeDtplUTvFzbI+3hIoYfYm8z9CXaSBzsCw2Kud6PD8Ob2AzQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -3740,7 +3769,7 @@ }, "engines": { "node": ">= 12.0.0", - "parcel": "^2.8.3" + "parcel": "^2.9.1" }, "funding": { "type": "opencollective", @@ -3757,33 +3786,34 @@ } }, "node_modules/@parcel/types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.3.tgz", - "integrity": "sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.1.tgz", + "integrity": "sha512-LBx4Tvr1sK9t+FmPjS4jPvcmUcJo6co22sn0pBuz2oXISs/YK2N+3ZHXL+KsozKvLn2wXysgaWFIARN9xFoORw==", "dev": true, "dependencies": { - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/package-manager": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/package-manager": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/workers": "2.8.3", + "@parcel/workers": "2.9.1", "utility-types": "^3.10.0" } }, "node_modules/@parcel/utils": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.3.tgz", - "integrity": "sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.1.tgz", + "integrity": "sha512-0P/zIvtvLyuzQA4VFMzA8F22lrUyGR+phve/NlBUH+4Tn+Rt/evh9fP9vG1YTVMXWd90tesLdrtqatm1hqrJSA==", "dev": true, "dependencies": { - "@parcel/codeframe": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/markdown-ansi": "2.8.3", + "@parcel/codeframe": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/markdown-ansi": "2.9.1", "@parcel/source-map": "^2.1.1", - "chalk": "^4.1.0" + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" }, "engines": { "node": ">= 12.0.0" @@ -3814,16 +3844,16 @@ } }, "node_modules/@parcel/workers": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.3.tgz", - "integrity": "sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.1.tgz", + "integrity": "sha512-24R4IRMX8TBghak6pDCzM5B8NB4LTt0pI4dwNqSENyZA/Q5s/xMbG5gdn4aTwkAyIQ5lHrgDsHzoHbjOT0HLYQ==", "dev": true, "dependencies": { - "@parcel/diagnostic": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "chrome-trace-event": "^1.0.2", + "@parcel/diagnostic": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/profiler": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" }, "engines": { @@ -3834,7 +3864,7 @@ "url": "https://opencollective.com/parcel" }, "peerDependencies": { - "@parcel/core": "^2.8.3" + "@parcel/core": "^2.9.1" } }, "node_modules/@pkgjs/parseargs": { @@ -4135,8 +4165,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -6596,16 +6624,16 @@ } }, "node_modules/css-select/node_modules/domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "optional": true, "peer": true, "dependencies": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" }, "funding": { "url": "https://github.com/fb55/domutils?sponsor=1" @@ -6662,105 +6690,6 @@ "node": ">=4" } }, - "node_modules/cssnano": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", - "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "cssnano-preset-default": "^6.0.1", - "lilconfig": "^2.1.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/cssnano" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", - "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^9.0.0", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.1", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/cssnano-preset-default/node_modules/postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.2" - } - }, - "node_modules/cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/csso": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", @@ -7020,8 +6949,9 @@ }, "node_modules/dom-serializer": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, - "license": "MIT", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -7031,6 +6961,15 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -7043,19 +6982,21 @@ }, "node_modules/domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/fb55" } - ], - "license": "BSD-2-Clause" + ] }, "node_modules/domhandler": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "domelementtype": "^2.2.0" }, @@ -7068,8 +7009,9 @@ }, "node_modules/domutils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "dom-serializer": "^1.0.1", "domelementtype": "^2.2.0", @@ -7181,9 +7123,13 @@ } }, "node_modules/entities": { - "version": "2.2.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true, - "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -8754,18 +8700,6 @@ "entities": "^3.0.1" } }, - "node_modules/htmlparser2/node_modules/entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", @@ -10625,25 +10559,37 @@ "license": "MIT" }, "node_modules/lmdb": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", - "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", "dev": true, "hasInstallScript": true, "dependencies": { - "msgpackr": "^1.5.4", + "msgpackr": "1.8.5", "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", "weak-lru-cache": "^1.2.2" }, + "bin": { + "download-lmdb-prebuilds": "bin/download-prebuilds.js" + }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "2.5.2", - "@lmdb/lmdb-darwin-x64": "2.5.2", - "@lmdb/lmdb-linux-arm": "2.5.2", - "@lmdb/lmdb-linux-arm64": "2.5.2", - "@lmdb/lmdb-linux-x64": "2.5.2", - "@lmdb/lmdb-win32-x64": "2.5.2" + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11" + } + }, + "node_modules/lmdb/node_modules/msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "dev": true, + "optionalDependencies": { + "msgpackr-extract": "^3.0.1" } }, "node_modules/lmdb/node_modules/node-addon-api": { @@ -11100,34 +11046,46 @@ "license": "MIT" }, "node_modules/msgpackr": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.2.tgz", - "integrity": "sha512-eLuPeok0DMwsGN23AvuVg32mYpx55tsQnxI87d8V1yZsdT8U5jrWhmCa1INO/joGAFQFfo/eTlM/BxVwLKbBOQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.2.tgz", + "integrity": "sha512-xtDgI3Xv0AAiZWLRGDchyzBwU6aq0rwJ+W+5Y4CZhEWtkl/hJtFFLc+3JtGTw7nz1yquxs7nL8q/yA2aqpflIQ==", "dev": true, "optionalDependencies": { - "msgpackr-extract": "^2.2.0" + "msgpackr-extract": "^3.0.2" } }, "node_modules/msgpackr-extract": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", - "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "dev": true, "hasInstallScript": true, "optional": true, "dependencies": { - "node-gyp-build-optional-packages": "5.0.3" + "node-gyp-build-optional-packages": "5.0.7" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + } + }, + "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build-optional-packages": "bin.js", + "node-gyp-build-optional-packages-optional": "optional.js", + "node-gyp-build-optional-packages-test": "build-test.js" } }, "node_modules/mz": { @@ -11235,9 +11193,9 @@ } }, "node_modules/node-gyp-build-optional-packages": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", - "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", "dev": true, "bin": { "node-gyp-build-optional-packages": "bin.js", @@ -11666,25 +11624,25 @@ } }, "node_modules/parcel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.3.tgz", - "integrity": "sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.9.1.tgz", + "integrity": "sha512-LBD+jeCpvnDJ8MeE0ciEns4EZw+WH01qLEKT2O1tW2uHM1njhcWvuc9bx19f8iyE2+8Xwwr2GsGTQgPXKiA/yQ==", "dev": true, "dependencies": { - "@parcel/config-default": "2.8.3", - "@parcel/core": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/reporter-cli": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/config-default": "2.9.1", + "@parcel/core": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/reporter-cli": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/reporter-tracer": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "commander": "^7.0.0", - "get-port": "^4.2.0", - "v8-compile-cache": "^2.0.0" + "get-port": "^4.2.0" }, "bin": { "parcel": "lib/bin.js" @@ -11980,100 +11938,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -12201,116 +12065,6 @@ "node": ">=10" } }, - "node_modules/postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-merge-rules": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", - "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-modules": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", @@ -12407,210 +12161,6 @@ "postcss": "^8.2.14" } }, - "node_modules/postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-reporter": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", @@ -12643,41 +12193,6 @@ "node": ">=4" } }, - "node_modules/postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - }, - "engines": { - "node": "^14 || ^16 || >= 18" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, - "node_modules/postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "postcss-selector-parser": "^6.0.5" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/postcss-value-parser": { "version": "4.2.0", "license": "MIT" @@ -14804,24 +14319,6 @@ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", "dev": true }, - "node_modules/stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^14 || ^16 || >=18.0" - }, - "peerDependencies": { - "postcss": "^8.2.15" - } - }, "node_modules/sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", @@ -15630,12 +15127,6 @@ "node": ">= 4" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -17741,44 +17232,44 @@ } }, "@lmdb/lmdb-darwin-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", - "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", "dev": true, "optional": true }, "@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", "dev": true, "optional": true }, "@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", "dev": true, "optional": true }, @@ -17810,44 +17301,44 @@ } }, "@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", - "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", - "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", - "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", - "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", - "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", - "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", "dev": true, "optional": true }, @@ -17875,107 +17366,108 @@ } }, "@parcel/bundler-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.8.3.tgz", - "integrity": "sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.1.tgz", + "integrity": "sha512-gNTaSQpp7jiFvkQ/P/KfAiVLT3UOEs5bBivQm4OMdgSi2DTIsjGMQVQ7JDzvzEzrHiFlDmdXKxUagex54pOtJg==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/cache": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.3.tgz", - "integrity": "sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.1.tgz", + "integrity": "sha512-2aFWUAi7vkcnIdfOw3oW/vhgvwv9MPb+LjmJSkE59nNUuSJe83jJFAPAhqQTHd9L3kX/Xk+xJBNYNubUq/Cieg==", "dev": true, "requires": { - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/utils": "2.8.3", - "lmdb": "2.5.2" + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/utils": "2.9.1", + "lmdb": "2.7.11" } }, "@parcel/codeframe": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", - "integrity": "sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.1.tgz", + "integrity": "sha512-qLVIyEHuZq8wWYaXVAwxMzlK3QqWlaB5fUSe1n+kITEa9EEwb2WPmysYAsWiVaFdD62A0+1klJ8Sq9gapOMIng==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/compressor-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz", - "integrity": "sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.1.tgz", + "integrity": "sha512-aUkZ0pOzGjQ9kyaUQ/suDVmU5lR4mT9fU5HXlp3hGD7MWh2HFJUOfQ3gp5g3P9x+MeVZKU+ht6UcIMhrzelLGQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/config-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.8.3.tgz", - "integrity": "sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.1.tgz", + "integrity": "sha512-oH6NHKaKp2YBHOcQJxwHGPbgGCZZZH1I4eef+KRBFiabgiDQxHLni+vg+c+mErd8lFrNn2gcGIdKzQwWqavT+w==", "dev": true, "requires": { - "@parcel/bundler-default": "2.8.3", - "@parcel/compressor-raw": "2.8.3", - "@parcel/namer-default": "2.8.3", - "@parcel/optimizer-css": "2.8.3", - "@parcel/optimizer-htmlnano": "2.8.3", - "@parcel/optimizer-image": "2.8.3", - "@parcel/optimizer-svgo": "2.8.3", - "@parcel/optimizer-terser": "2.8.3", - "@parcel/packager-css": "2.8.3", - "@parcel/packager-html": "2.8.3", - "@parcel/packager-js": "2.8.3", - "@parcel/packager-raw": "2.8.3", - "@parcel/packager-svg": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/resolver-default": "2.8.3", - "@parcel/runtime-browser-hmr": "2.8.3", - "@parcel/runtime-js": "2.8.3", - "@parcel/runtime-react-refresh": "2.8.3", - "@parcel/runtime-service-worker": "2.8.3", - "@parcel/transformer-babel": "2.8.3", - "@parcel/transformer-css": "2.8.3", - "@parcel/transformer-html": "2.8.3", - "@parcel/transformer-image": "2.8.3", - "@parcel/transformer-js": "2.8.3", - "@parcel/transformer-json": "2.8.3", - "@parcel/transformer-postcss": "2.8.3", - "@parcel/transformer-posthtml": "2.8.3", - "@parcel/transformer-raw": "2.8.3", - "@parcel/transformer-react-refresh-wrap": "2.8.3", - "@parcel/transformer-svg": "2.8.3" + "@parcel/bundler-default": "2.9.1", + "@parcel/compressor-raw": "2.9.1", + "@parcel/namer-default": "2.9.1", + "@parcel/optimizer-css": "2.9.1", + "@parcel/optimizer-htmlnano": "2.9.1", + "@parcel/optimizer-image": "2.9.1", + "@parcel/optimizer-svgo": "2.9.1", + "@parcel/optimizer-swc": "2.9.1", + "@parcel/packager-css": "2.9.1", + "@parcel/packager-html": "2.9.1", + "@parcel/packager-js": "2.9.1", + "@parcel/packager-raw": "2.9.1", + "@parcel/packager-svg": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/resolver-default": "2.9.1", + "@parcel/runtime-browser-hmr": "2.9.1", + "@parcel/runtime-js": "2.9.1", + "@parcel/runtime-react-refresh": "2.9.1", + "@parcel/runtime-service-worker": "2.9.1", + "@parcel/transformer-babel": "2.9.1", + "@parcel/transformer-css": "2.9.1", + "@parcel/transformer-html": "2.9.1", + "@parcel/transformer-image": "2.9.1", + "@parcel/transformer-js": "2.9.1", + "@parcel/transformer-json": "2.9.1", + "@parcel/transformer-postcss": "2.9.1", + "@parcel/transformer-posthtml": "2.9.1", + "@parcel/transformer-raw": "2.9.1", + "@parcel/transformer-react-refresh-wrap": "2.9.1", + "@parcel/transformer-svg": "2.9.1" } }, "@parcel/core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.3.tgz", - "integrity": "sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.1.tgz", + "integrity": "sha512-D/7iyRV5c8kYMV1JGkokktxh3ON5CMvNAllaBucl4SMatAyLo5aLjGG5ey6FD/4Tv+JJ6NsldLtkvciDVJdgFQ==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/profiler": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", @@ -17997,9 +17489,9 @@ } }, "@parcel/diagnostic": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.3.tgz", - "integrity": "sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.1.tgz", + "integrity": "sha512-LM+w4maoAsjcL+javaHw9B9oEQoLdg/fMCNbuTmAKpQWi16hfNkr4+xz7AxxwL3dCcL7uuvVgoUOUubwxWNLAA==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", @@ -18007,90 +17499,88 @@ } }, "@parcel/events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.3.tgz", - "integrity": "sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.1.tgz", + "integrity": "sha512-tga4FiJB1TC4iOKBK66e9zXpcDFXvJhXmsgOMsgSTM6uCZMXeGaYEixHNlPDs3HTfg17qAmHHlhfgPBbku/aOg==", "dev": true }, "@parcel/fs": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.3.tgz", - "integrity": "sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.1.tgz", + "integrity": "sha512-F/GRHtHN4AuTauadsq/UQ1OSpLBLAS/96Sv1x09/AKZxNlZ2UzWExoYEhSkVM5smKVzSnx8XP9OqABcHcZwOLQ==", "dev": true, "requires": { - "@parcel/fs-search": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/fs-search": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "@parcel/watcher": "^2.0.7", - "@parcel/workers": "2.8.3" + "@parcel/workers": "2.9.1" } }, "@parcel/fs-search": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.3.tgz", - "integrity": "sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3" - } + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.1.tgz", + "integrity": "sha512-F7SkVsMb5XYcWmeptLz5D3g76Raed3dmNulJMrWIECP8lJ1LUcCExQId7NsdeCfRbNRwaf84gdsjc/1GKM/QYg==", + "dev": true }, "@parcel/graph": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.3.tgz", - "integrity": "sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.1.tgz", + "integrity": "sha512-fc/Yk1XPzo3ZHhKS7l5aETAEBpnF0nK+0TawkNrQ2rcL21MG1kHNYSR8uBwOqyXmBSMEItals5Ixgd8fWa+9PQ==", "dev": true, "requires": { "nullthrows": "^1.1.1" } }, "@parcel/hash": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.3.tgz", - "integrity": "sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.1.tgz", + "integrity": "sha512-fiqAIi/23h5tnH5W7DRTwOhfRPhadHvI7hYoG8YFGvnFxSQ/XCnOID0B0/vNhaluICSPeFcedjAmDVdqY6/X7w==", "dev": true, "requires": { - "detect-libc": "^1.0.3", "xxhash-wasm": "^0.4.2" } }, "@parcel/logger": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.3.tgz", - "integrity": "sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.1.tgz", + "integrity": "sha512-wUH9ShrRr3RwNa75ymegDIAdJiY3dGB7HCgIP6VOOc2CGyGA2DJKbbYGfw5mkl3DV8lUV+dYsWYMGXZhInAQCQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1" } }, "@parcel/markdown-ansi": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz", - "integrity": "sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.1.tgz", + "integrity": "sha512-FpOz2ltnKnm6QaQCdcpuAEwGuScVUq0ixT/QAmU7A3/cwlsoxqMkB2XeWYIVTjs7p7Bsu0Ctdid/6pdtP7ghpg==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/namer-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.8.3.tgz", - "integrity": "sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.1.tgz", + "integrity": "sha512-XHpAc5JLQchUqRrYqnUvinReR2nCyiD+DhIedMW5hURwlCPBlfcTVf6M5kSSpjzqRDVKezx3TFF6dzZNv0fBJQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/node-resolver-core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz", - "integrity": "sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.1.tgz", + "integrity": "sha512-4owokOoHCONeazQGndB4PkIaUhZfyWuCT7Sx4UJc2UhR1V82MlahHrT2ItT0pkQyKWwCSNgHdBgdKUgKRdIiAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/utils": "2.8.3", + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "semver": "^5.7.1" }, @@ -18104,27 +17594,27 @@ } }, "@parcel/optimizer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz", - "integrity": "sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.1.tgz", + "integrity": "sha512-IYQpV0kc0KN/aqRAWQsZ8b2pbI4ha4T5HAi27lTGIhQNvEixUtf0gJvCJVSlBxpdMiXVJq9pp97UamoNuB6oig==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/optimizer-htmlnano": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz", - "integrity": "sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.1.tgz", + "integrity": "sha512-t/e9XsoXZViqOFWcz3LlEClCOYNCjP6MIo+p+WmAuc5+QFF0/9viNqgRbhVe8V1tbtRofxsm4BossFOjOBSjmg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", @@ -18187,27 +17677,26 @@ } }, "@parcel/optimizer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz", - "integrity": "sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.1.tgz", + "integrity": "sha512-Ml51RUGbQXyoHZ9yhyal8J/khZeWZX5J8NPOEvkCmmOkxo/qM4CMPIvJStzzn5K7mOPRKUheDkM/QoNGO5gTwA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "detect-libc": "^1.0.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1" } }, "@parcel/optimizer-svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz", - "integrity": "sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.1.tgz", + "integrity": "sha512-8XHSEIjJfdTFtUQzRiy0K+fbvdcheYc+azdyuJPnIV5AX04k4heKwp7uH328Ylk2k0JkfDyQmjFEyPj9qWDadQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "svgo": "^2.4.0" }, "dependencies": { @@ -18266,32 +17755,33 @@ } } }, - "@parcel/optimizer-terser": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz", - "integrity": "sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==", + "@parcel/optimizer-swc": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.1.tgz", + "integrity": "sha512-bLDkAwkmFE8YZNHcfJNj22haSLXrqjZkGXbPgGDkanCUS52yWv1+OFZ+6frX2q4EdXaTX8nFZSJL4VPHZZiUGQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "nullthrows": "^1.1.1", - "terser": "^5.2.0" + "@parcel/utils": "2.9.1", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" } }, "@parcel/package-manager": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.3.tgz", - "integrity": "sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.1.tgz", + "integrity": "sha512-cTUBUPRm62770Vw4YG5WGlkFxJII320nSobbP0TMggE/CGXg3ru2pvvX6WqXTFAHeM/z78xTPDq0NP97DBp5Ow==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/node-resolver-core": "3.0.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "semver": "^5.7.1" }, "dependencies": { @@ -18304,49 +17794,50 @@ } }, "@parcel/packager-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.8.3.tgz", - "integrity": "sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.1.tgz", + "integrity": "sha512-efMShrIwVBY9twZTGQ5QFwl9H3xJg8nSjl/xgOGq9rrbkmcrVlfSgPL9ExNx75EvmOwOKxZjFiMsNYNICPNfgg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/packager-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.8.3.tgz", - "integrity": "sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.1.tgz", + "integrity": "sha512-mP7iIwyFDZ21XwD2SlwZoSrvKpS5Amlpi/ywd0dLdwQb5TL+Q2f05IcRNfFbWdVd1AJycDQ85ERokNKN3QPMkg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" } }, "@parcel/packager-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.8.3.tgz", - "integrity": "sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.1.tgz", + "integrity": "sha512-MmeKdp/obO36M8Y9yYAFiFkdhRFbQtYGSxbMwm2JVtRKMcFmlR5KzqLUg67OX6qgKw5lZZ1TkYhSI0hQQ6+Vqw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "globals": "^13.2.0", "nullthrows": "^1.1.1" }, "dependencies": { "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -18355,109 +17846,133 @@ } }, "@parcel/packager-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.8.3.tgz", - "integrity": "sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.1.tgz", + "integrity": "sha512-qHJ389R5cLgR2PcJt8sOrNBcAY0qpZRMTOMgkc9zYkKy1tdUMgCUuDfO1kShfv4E7rr084mtlu9tK8MXChyF6w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/packager-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.8.3.tgz", - "integrity": "sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.1.tgz", + "integrity": "sha512-aRzuiwcUlNATfSIbeYpDkJXvwdiAAbiQlxSz6cI53NqWwZn+Dn79WyiKPBST14ij4/P3ZjkcwXevqHpvXP/ArQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "posthtml": "^0.16.4" } }, "@parcel/plugin": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.3.tgz", - "integrity": "sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.1.tgz", + "integrity": "sha512-kD+BNkPGRcxZZUKhAXqF/bilUMhXUlf/ZixVlBS5rEsUB1yx/Ze8c4ypaKr5WsEwv34C+X4p4WFYdZVJEr3Y+g==", "dev": true, "requires": { - "@parcel/types": "2.8.3" + "@parcel/types": "2.9.1" + } + }, + "@parcel/profiler": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.1.tgz", + "integrity": "sha512-hrptwbh9uUxnWHAAXiZ6BtpM74cU+VfrOWgnmUA8pkYWBmrb2wSLeqRKl8FiSt+nfRTTbNAIlmn9vk2x+wRNOA==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "chrome-trace-event": "^1.0.2" } }, "@parcel/reporter-cli": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz", - "integrity": "sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.9.1.tgz", + "integrity": "sha512-xzJaaHQwcsmHijlCl7gOAdqU0n6AnW7c7rN8AXDH8BvnOx2v8NC8nCIEmDTOfpQYepcuER2+ilTQ7jpDx/iDhg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "term-size": "^2.2.1" } }, "@parcel/reporter-dev-server": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz", - "integrity": "sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.1.tgz", + "integrity": "sha512-Wa9kmtnuYTqEsKakhrSLvZmWxM4TB+Dg2jl1vC3gYfvlsgt/d/Hp/y2giPH1EeCm4wEEQfdAY3WmSUx9p1x07w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" + } + }, + "@parcel/reporter-tracer": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.9.1.tgz", + "integrity": "sha512-LgZKx9qwBAChWHBcpHW8GJXz45IGtiPmzs6HIDavZOiGqjGVzmbHUKxHnFaRZqR6WznJ+0ay/2o+BrJ8cyXUcg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" } }, "@parcel/resolver-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.8.3.tgz", - "integrity": "sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.1.tgz", + "integrity": "sha512-Q+knNaRDTbGIGqUnddtWEgpYduVBkDyi/CpxKpi7dP7sVYNJsXwEf82hpjX6/XqotA5dehT63yJkvJ/wxJF1Nw==", "dev": true, "requires": { - "@parcel/node-resolver-core": "2.8.3", - "@parcel/plugin": "2.8.3" + "@parcel/node-resolver-core": "3.0.1", + "@parcel/plugin": "2.9.1" } }, "@parcel/runtime-browser-hmr": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz", - "integrity": "sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.1.tgz", + "integrity": "sha512-C+023FOsrycpBHUgUf7Nv4uN0NrLN3UkeymsAHQlgZD5QQD7+nhG6p9PQ7+HbbEAaGaeO7c/86s2qRUglufNig==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" } }, "@parcel/runtime-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.8.3.tgz", - "integrity": "sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.1.tgz", + "integrity": "sha512-caT1s1BqYNFGFAz9ul7uwDf+ZXzipiYYoHphhmT2JFweQmRA1CrMeFCuCQa2exsdu+UQpRbuKd+v5UUS2n0poQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/runtime-react-refresh": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz", - "integrity": "sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.1.tgz", + "integrity": "sha512-opDW9p3f4gVc1aVdFAyLWTL+2S8rhsPdBQRBHEi4WE2DRe/9lpA12NN5KUUHy88dlIr3wyzmaO2Fts0r/x80zg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-error-overlay": "6.0.9", "react-refresh": "^0.9.0" } }, "@parcel/runtime-service-worker": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz", - "integrity": "sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.1.tgz", + "integrity": "sha512-TED4MouYjP7xbU9V7/3rjnmuWbCefrP+OC+eQJG6j3HwKiL92QTZ6trWqdLuxFhtZMXKjwbWaBBbIcELB/PbtQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -18471,15 +17986,15 @@ } }, "@parcel/transformer-babel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz", - "integrity": "sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.1.tgz", + "integrity": "sha512-HEU3bavD9Cu0RP5T1ioGLbsOQDqND/SQWal8L2f9HsgwTs2kzmTxYylNccqNjAMj3NnoyXzKMKbZyG8qEuLlpw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -18495,29 +18010,29 @@ } }, "@parcel/transformer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.8.3.tgz", - "integrity": "sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.1.tgz", + "integrity": "sha512-nT+xOfyveX6qSb088dOh59HWJ1gm7DAIQZPbjTa1wLzRQul8ysdQRf/loulBmtUheol7YwQtVvUHN2XgoMDCAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.8.3.tgz", - "integrity": "sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.1.tgz", + "integrity": "sha512-pIkJbcB91Dl2RyZmVd9neGkf7XJeYXwgx0et5hktw+3m0S2QB399OjVWwi5Q6ZdtTrWkQnHLmbeHT3NOmNWlaw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -18535,45 +18050,35 @@ } }, "@parcel/transformer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.8.3.tgz", - "integrity": "sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.1.tgz", + "integrity": "sha512-3D4zEavCM1i354ZgJWg7RBNgASA7Q2iHN374lH5hT6I7VAJzNT+PTNrPNQ4vKhi69r+i1sQQzsPdgEUXOExmbQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.8.3.tgz", - "integrity": "sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.1.tgz", + "integrity": "sha512-7hlbAIufIvx6iPspfZ3v1g2cmtpaNEaC04RzRv8HVVru8TE868yplFI840ZBnF5ylOfmxwFTUjlphVtVcPs13A==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "@swc/helpers": "^0.4.12", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", + "@swc/helpers": "^0.5.0", "browserslist": "^4.6.6", - "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", "regenerator-runtime": "^0.13.7", "semver": "^5.7.1" }, "dependencies": { - "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dev": true, - "requires": { - "tslib": "^2.4.0" - } - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -18583,25 +18088,25 @@ } }, "@parcel/transformer-json": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.8.3.tgz", - "integrity": "sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.1.tgz", + "integrity": "sha512-yFRSz1qVbdCssC65D37Ru3diQk7GQl5ZOOyQ7MeMYlhvl8mcFKGRC3wUAyqBZrh70VOWuWR7WS2XLdqTdE9WqQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "json5": "^2.2.0" } }, "@parcel/transformer-postcss": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz", - "integrity": "sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.1.tgz", + "integrity": "sha512-sNSJbdT4Z8H+/cZ/vCmos44SfbB9O5gNgMEgGa6WqU7MV7cVlnE8zuNJkxR97ZZTpIXNrfVerOY3lOrUrFCxdA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "clone": "^2.1.1", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", @@ -18617,13 +18122,13 @@ } }, "@parcel/transformer-posthtml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz", - "integrity": "sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.1.tgz", + "integrity": "sha512-I6fr6lVAqjDxdkOwxelx7FibMWP55JPf3ZTXKCWpoIGkOuT2i2tYZMdXEHVshZWJmByelbYSC96w8P8rSY+6XQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -18640,34 +18145,34 @@ } }, "@parcel/transformer-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz", - "integrity": "sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.1.tgz", + "integrity": "sha512-Wr0Y9fETiyF5ntL3yhn/ZXjcnswcn1T9YLXa+yAxpAxKW+/D7A1jKVS0tyDOZsdakWA9gzlLP6w1O4Nl8pVmEg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/transformer-react-refresh-wrap": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz", - "integrity": "sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.1.tgz", + "integrity": "sha512-ML+KDvLoZ6O+9r3/yf8DeVtobhYc9DPXYHZ75aXoFyou97I9WDf4EqlY4/MSkbZV79FUXxC68dyLJj3Q9ILqeA==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-refresh": "^0.9.0" } }, "@parcel/transformer-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz", - "integrity": "sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.1.tgz", + "integrity": "sha512-DYcUfutjtghPXMVybFygncIKJl/4rrpQMxv8yTVeDtplUTvFzbI+3hIoYfYm8z9CXaSBzsCw2Kud6PD8Ob2AzQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -18684,33 +18189,34 @@ } }, "@parcel/types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.3.tgz", - "integrity": "sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.1.tgz", + "integrity": "sha512-LBx4Tvr1sK9t+FmPjS4jPvcmUcJo6co22sn0pBuz2oXISs/YK2N+3ZHXL+KsozKvLn2wXysgaWFIARN9xFoORw==", "dev": true, "requires": { - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/package-manager": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/package-manager": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/workers": "2.8.3", + "@parcel/workers": "2.9.1", "utility-types": "^3.10.0" } }, "@parcel/utils": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.3.tgz", - "integrity": "sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.1.tgz", + "integrity": "sha512-0P/zIvtvLyuzQA4VFMzA8F22lrUyGR+phve/NlBUH+4Tn+Rt/evh9fP9vG1YTVMXWd90tesLdrtqatm1hqrJSA==", "dev": true, "requires": { - "@parcel/codeframe": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/markdown-ansi": "2.8.3", + "@parcel/codeframe": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/markdown-ansi": "2.9.1", "@parcel/source-map": "^2.1.1", - "chalk": "^4.1.0" + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" } }, "@parcel/watcher": { @@ -18726,16 +18232,16 @@ } }, "@parcel/workers": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.3.tgz", - "integrity": "sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.1.tgz", + "integrity": "sha512-24R4IRMX8TBghak6pDCzM5B8NB4LTt0pI4dwNqSENyZA/Q5s/xMbG5gdn4aTwkAyIQ5lHrgDsHzoHbjOT0HLYQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "chrome-trace-event": "^1.0.2", + "@parcel/diagnostic": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/profiler": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -18896,8 +18402,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, - "optional": true, - "peer": true, "requires": { "tslib": "^2.4.0" } @@ -18942,7 +18446,7 @@ "@tailwindcss/integrations-parcel": { "version": "file:integrations/parcel", "requires": { - "parcel": "^2.8.3" + "parcel": "2.9.1" } }, "@tailwindcss/integrations-postcss-cli": { @@ -21203,16 +20707,16 @@ } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "optional": true, "peer": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "entities": { @@ -21246,80 +20750,6 @@ "cssesc": { "version": "3.0.0" }, - "cssnano": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", - "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "cssnano-preset-default": "^6.0.1", - "lilconfig": "^2.1.0" - } - }, - "cssnano-preset-default": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", - "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^9.0.0", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.1", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - }, - "dependencies": { - "postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0" - } - } - } - }, - "cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, "csso": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", @@ -21508,11 +20938,21 @@ }, "dom-serializer": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } } }, "domain-browser": { @@ -21523,10 +20963,14 @@ }, "domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, "domhandler": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "requires": { "domelementtype": "^2.2.0" @@ -21534,6 +20978,8 @@ }, "domutils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, "requires": { "dom-serializer": "^1.0.1", @@ -21629,7 +21075,9 @@ } }, "entities": { - "version": "2.2.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true }, "envinfo": { @@ -22745,14 +22193,6 @@ "domhandler": "^4.2.2", "domutils": "^2.8.0", "entities": "^3.0.1" - }, - "dependencies": { - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true - } } }, "http-cache-semantics": { @@ -24147,24 +23587,33 @@ "version": "1.2.4" }, "lmdb": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", - "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", "dev": true, "requires": { - "@lmdb/lmdb-darwin-arm64": "2.5.2", - "@lmdb/lmdb-darwin-x64": "2.5.2", - "@lmdb/lmdb-linux-arm": "2.5.2", - "@lmdb/lmdb-linux-arm64": "2.5.2", - "@lmdb/lmdb-linux-x64": "2.5.2", - "@lmdb/lmdb-win32-x64": "2.5.2", - "msgpackr": "^1.5.4", + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11", + "msgpackr": "1.8.5", "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", "weak-lru-cache": "^1.2.2" }, "dependencies": { + "msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "dev": true, + "requires": { + "msgpackr-extract": "^3.0.1" + } + }, "node-addon-api": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", @@ -24518,28 +23967,37 @@ "dev": true }, "msgpackr": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.2.tgz", - "integrity": "sha512-eLuPeok0DMwsGN23AvuVg32mYpx55tsQnxI87d8V1yZsdT8U5jrWhmCa1INO/joGAFQFfo/eTlM/BxVwLKbBOQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.2.tgz", + "integrity": "sha512-xtDgI3Xv0AAiZWLRGDchyzBwU6aq0rwJ+W+5Y4CZhEWtkl/hJtFFLc+3JtGTw7nz1yquxs7nL8q/yA2aqpflIQ==", "dev": true, "requires": { - "msgpackr-extract": "^2.2.0" + "msgpackr-extract": "^3.0.2" } }, "msgpackr-extract": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", - "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "dev": true, "optional": true, "requires": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0", - "node-gyp-build-optional-packages": "5.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2", + "node-gyp-build-optional-packages": "5.0.7" + }, + "dependencies": { + "node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "dev": true, + "optional": true + } } }, "mz": { @@ -24615,9 +24073,9 @@ "dev": true }, "node-gyp-build-optional-packages": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", - "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", "dev": true }, "node-int64": { @@ -24941,25 +24399,25 @@ } }, "parcel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.3.tgz", - "integrity": "sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.9.1.tgz", + "integrity": "sha512-LBD+jeCpvnDJ8MeE0ciEns4EZw+WH01qLEKT2O1tW2uHM1njhcWvuc9bx19f8iyE2+8Xwwr2GsGTQgPXKiA/yQ==", "dev": true, "requires": { - "@parcel/config-default": "2.8.3", - "@parcel/core": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/reporter-cli": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/config-default": "2.9.1", + "@parcel/core": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/reporter-cli": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/reporter-tracer": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "commander": "^7.0.0", - "get-port": "^4.2.0", - "v8-compile-cache": "^2.0.0" + "get-port": "^4.2.0" } }, "parent-module": { @@ -25143,68 +24601,6 @@ } } }, - "postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, "postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -25274,80 +24670,6 @@ } } }, - "postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - } - }, - "postcss-merge-rules": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", - "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-modules": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", @@ -25408,139 +24730,6 @@ "postcss-selector-parser": "^6.0.11" } }, - "postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, "postcss-reporter": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", @@ -25560,29 +24749,6 @@ "util-deprecate": "^1.0.2" } }, - "postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - } - }, - "postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-value-parser": { "version": "4.2.0" }, @@ -27119,18 +26285,6 @@ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", "dev": true }, - "stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - } - }, "sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", @@ -28464,44 +27618,44 @@ } }, "@lmdb/lmdb-darwin-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz", - "integrity": "sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.7.11.tgz", + "integrity": "sha512-r6+vYq2vKzE+vgj/rNVRMwAevq0+ZR9IeMFIqcSga+wMtMdXQ27KqQ7uS99/yXASg29bos7yHP3yk4x6Iio0lw==", "dev": true, "optional": true }, "@lmdb/lmdb-darwin-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz", - "integrity": "sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.7.11.tgz", + "integrity": "sha512-jhj1aB4K8ycRL1HOQT5OtzlqOq70jxUQEWRN9Gqh3TIDN30dxXtiHi6EWF516tzw6v2+3QqhDMJh8O6DtTGG8Q==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz", - "integrity": "sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.7.11.tgz", + "integrity": "sha512-dHfLFVSrw/v5X5lkwp0Vl7+NFpEeEYKfMG2DpdFJnnG1RgHQZngZxCaBagFoaJGykRpd2DYF1AeuXBFrAUAXfw==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-arm64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz", - "integrity": "sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.7.11.tgz", + "integrity": "sha512-7xGEfPPbmVJWcY2Nzqo11B9Nfxs+BAsiiaY/OcT4aaTDdykKeCjvKMQJA3KXCtZ1AtiC9ljyGLi+BfUwdulY5A==", "dev": true, "optional": true }, "@lmdb/lmdb-linux-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz", - "integrity": "sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.7.11.tgz", + "integrity": "sha512-vUKI3JrREMQsXX8q0Eq5zX2FlYCKWMmLiCyyJNfZK0Uyf14RBg9VtB3ObQ41b4swYh2EWaltasWVe93Y8+KDng==", "dev": true, "optional": true }, "@lmdb/lmdb-win32-x64": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz", - "integrity": "sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.7.11.tgz", + "integrity": "sha512-BJwkHlSUgtB+Ei52Ai32M1AOMerSlzyIGA/KC4dAGL+GGwVMdwG8HGCOA2TxP3KjhbgDPMYkv7bt/NmOmRIFng==", "dev": true, "optional": true }, @@ -28533,44 +27687,44 @@ } }, "@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.2.0.tgz", - "integrity": "sha512-Z9LFPzfoJi4mflGWV+rv7o7ZbMU5oAU9VmzCgL240KnqDW65Y2HFCT3MW06/ITJSnbVLacmcEJA8phywK7JinQ==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", + "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-2.2.0.tgz", - "integrity": "sha512-vq0tT8sjZsy4JdSqmadWVw6f66UXqUCabLmUVHZwUFzMgtgoIIQjT4VVRHKvlof3P/dMCkbMJ5hB1oJ9OWHaaw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", + "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-2.2.0.tgz", - "integrity": "sha512-SaJ3Qq4lX9Syd2xEo9u3qPxi/OB+5JO/ngJKK97XDpa1C587H9EWYO6KD8995DAjSinWvdHKRrCOXVUC5fvGOg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", + "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-2.2.0.tgz", - "integrity": "sha512-hlxxLdRmPyq16QCutUtP8Tm6RDWcyaLsRssaHROatgnkOxdleMTgetf9JsdncL8vLh7FVy/RN9i3XR5dnb9cRA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", + "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-2.2.0.tgz", - "integrity": "sha512-94y5PJrSOqUNcFKmOl7z319FelCLAE0rz/jPCWS+UtdMZvpa4jrQd+cJPQCLp2Fes1yAW/YUQj/Di6YVT3c3Iw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", + "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", "dev": true, "optional": true }, "@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-2.2.0.tgz", - "integrity": "sha512-XrC0JzsqQSvOyM3t04FMLO6z5gCuhPE6k4FXuLK5xf52ZbdvcFe1yBmo7meCew9B8G2f0T9iu9t3kfTYRYROgA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", + "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", "dev": true, "optional": true }, @@ -28598,107 +27752,108 @@ } }, "@parcel/bundler-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.8.3.tgz", - "integrity": "sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/bundler-default/-/bundler-default-2.9.1.tgz", + "integrity": "sha512-gNTaSQpp7jiFvkQ/P/KfAiVLT3UOEs5bBivQm4OMdgSi2DTIsjGMQVQ7JDzvzEzrHiFlDmdXKxUagex54pOtJg==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/cache": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.8.3.tgz", - "integrity": "sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/cache/-/cache-2.9.1.tgz", + "integrity": "sha512-2aFWUAi7vkcnIdfOw3oW/vhgvwv9MPb+LjmJSkE59nNUuSJe83jJFAPAhqQTHd9L3kX/Xk+xJBNYNubUq/Cieg==", "dev": true, "requires": { - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/utils": "2.8.3", - "lmdb": "2.5.2" + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/utils": "2.9.1", + "lmdb": "2.7.11" } }, "@parcel/codeframe": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.8.3.tgz", - "integrity": "sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/codeframe/-/codeframe-2.9.1.tgz", + "integrity": "sha512-qLVIyEHuZq8wWYaXVAwxMzlK3QqWlaB5fUSe1n+kITEa9EEwb2WPmysYAsWiVaFdD62A0+1klJ8Sq9gapOMIng==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/compressor-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz", - "integrity": "sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/compressor-raw/-/compressor-raw-2.9.1.tgz", + "integrity": "sha512-aUkZ0pOzGjQ9kyaUQ/suDVmU5lR4mT9fU5HXlp3hGD7MWh2HFJUOfQ3gp5g3P9x+MeVZKU+ht6UcIMhrzelLGQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/config-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.8.3.tgz", - "integrity": "sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/config-default/-/config-default-2.9.1.tgz", + "integrity": "sha512-oH6NHKaKp2YBHOcQJxwHGPbgGCZZZH1I4eef+KRBFiabgiDQxHLni+vg+c+mErd8lFrNn2gcGIdKzQwWqavT+w==", "dev": true, "requires": { - "@parcel/bundler-default": "2.8.3", - "@parcel/compressor-raw": "2.8.3", - "@parcel/namer-default": "2.8.3", - "@parcel/optimizer-css": "2.8.3", - "@parcel/optimizer-htmlnano": "2.8.3", - "@parcel/optimizer-image": "2.8.3", - "@parcel/optimizer-svgo": "2.8.3", - "@parcel/optimizer-terser": "2.8.3", - "@parcel/packager-css": "2.8.3", - "@parcel/packager-html": "2.8.3", - "@parcel/packager-js": "2.8.3", - "@parcel/packager-raw": "2.8.3", - "@parcel/packager-svg": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/resolver-default": "2.8.3", - "@parcel/runtime-browser-hmr": "2.8.3", - "@parcel/runtime-js": "2.8.3", - "@parcel/runtime-react-refresh": "2.8.3", - "@parcel/runtime-service-worker": "2.8.3", - "@parcel/transformer-babel": "2.8.3", - "@parcel/transformer-css": "2.8.3", - "@parcel/transformer-html": "2.8.3", - "@parcel/transformer-image": "2.8.3", - "@parcel/transformer-js": "2.8.3", - "@parcel/transformer-json": "2.8.3", - "@parcel/transformer-postcss": "2.8.3", - "@parcel/transformer-posthtml": "2.8.3", - "@parcel/transformer-raw": "2.8.3", - "@parcel/transformer-react-refresh-wrap": "2.8.3", - "@parcel/transformer-svg": "2.8.3" + "@parcel/bundler-default": "2.9.1", + "@parcel/compressor-raw": "2.9.1", + "@parcel/namer-default": "2.9.1", + "@parcel/optimizer-css": "2.9.1", + "@parcel/optimizer-htmlnano": "2.9.1", + "@parcel/optimizer-image": "2.9.1", + "@parcel/optimizer-svgo": "2.9.1", + "@parcel/optimizer-swc": "2.9.1", + "@parcel/packager-css": "2.9.1", + "@parcel/packager-html": "2.9.1", + "@parcel/packager-js": "2.9.1", + "@parcel/packager-raw": "2.9.1", + "@parcel/packager-svg": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/resolver-default": "2.9.1", + "@parcel/runtime-browser-hmr": "2.9.1", + "@parcel/runtime-js": "2.9.1", + "@parcel/runtime-react-refresh": "2.9.1", + "@parcel/runtime-service-worker": "2.9.1", + "@parcel/transformer-babel": "2.9.1", + "@parcel/transformer-css": "2.9.1", + "@parcel/transformer-html": "2.9.1", + "@parcel/transformer-image": "2.9.1", + "@parcel/transformer-js": "2.9.1", + "@parcel/transformer-json": "2.9.1", + "@parcel/transformer-postcss": "2.9.1", + "@parcel/transformer-posthtml": "2.9.1", + "@parcel/transformer-raw": "2.9.1", + "@parcel/transformer-react-refresh-wrap": "2.9.1", + "@parcel/transformer-svg": "2.9.1" } }, "@parcel/core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.8.3.tgz", - "integrity": "sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/core/-/core-2.9.1.tgz", + "integrity": "sha512-D/7iyRV5c8kYMV1JGkokktxh3ON5CMvNAllaBucl4SMatAyLo5aLjGG5ey6FD/4Tv+JJ6NsldLtkvciDVJdgFQ==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/graph": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/graph": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/profiler": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "abortcontroller-polyfill": "^1.1.9", "base-x": "^3.0.8", "browserslist": "^4.6.6", @@ -28720,9 +27875,9 @@ } }, "@parcel/diagnostic": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.8.3.tgz", - "integrity": "sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/diagnostic/-/diagnostic-2.9.1.tgz", + "integrity": "sha512-LM+w4maoAsjcL+javaHw9B9oEQoLdg/fMCNbuTmAKpQWi16hfNkr4+xz7AxxwL3dCcL7uuvVgoUOUubwxWNLAA==", "dev": true, "requires": { "@mischnic/json-sourcemap": "^0.1.0", @@ -28730,90 +27885,88 @@ } }, "@parcel/events": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.8.3.tgz", - "integrity": "sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/events/-/events-2.9.1.tgz", + "integrity": "sha512-tga4FiJB1TC4iOKBK66e9zXpcDFXvJhXmsgOMsgSTM6uCZMXeGaYEixHNlPDs3HTfg17qAmHHlhfgPBbku/aOg==", "dev": true }, "@parcel/fs": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.8.3.tgz", - "integrity": "sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs/-/fs-2.9.1.tgz", + "integrity": "sha512-F/GRHtHN4AuTauadsq/UQ1OSpLBLAS/96Sv1x09/AKZxNlZ2UzWExoYEhSkVM5smKVzSnx8XP9OqABcHcZwOLQ==", "dev": true, "requires": { - "@parcel/fs-search": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/fs-search": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "@parcel/watcher": "^2.0.7", - "@parcel/workers": "2.8.3" + "@parcel/workers": "2.9.1" } }, "@parcel/fs-search": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.8.3.tgz", - "integrity": "sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ==", - "dev": true, - "requires": { - "detect-libc": "^1.0.3" - } + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/fs-search/-/fs-search-2.9.1.tgz", + "integrity": "sha512-F7SkVsMb5XYcWmeptLz5D3g76Raed3dmNulJMrWIECP8lJ1LUcCExQId7NsdeCfRbNRwaf84gdsjc/1GKM/QYg==", + "dev": true }, "@parcel/graph": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.8.3.tgz", - "integrity": "sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/graph/-/graph-2.9.1.tgz", + "integrity": "sha512-fc/Yk1XPzo3ZHhKS7l5aETAEBpnF0nK+0TawkNrQ2rcL21MG1kHNYSR8uBwOqyXmBSMEItals5Ixgd8fWa+9PQ==", "dev": true, "requires": { "nullthrows": "^1.1.1" } }, "@parcel/hash": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.8.3.tgz", - "integrity": "sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/hash/-/hash-2.9.1.tgz", + "integrity": "sha512-fiqAIi/23h5tnH5W7DRTwOhfRPhadHvI7hYoG8YFGvnFxSQ/XCnOID0B0/vNhaluICSPeFcedjAmDVdqY6/X7w==", "dev": true, "requires": { - "detect-libc": "^1.0.3", "xxhash-wasm": "^0.4.2" } }, "@parcel/logger": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.8.3.tgz", - "integrity": "sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/logger/-/logger-2.9.1.tgz", + "integrity": "sha512-wUH9ShrRr3RwNa75ymegDIAdJiY3dGB7HCgIP6VOOc2CGyGA2DJKbbYGfw5mkl3DV8lUV+dYsWYMGXZhInAQCQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1" } }, "@parcel/markdown-ansi": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz", - "integrity": "sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/markdown-ansi/-/markdown-ansi-2.9.1.tgz", + "integrity": "sha512-FpOz2ltnKnm6QaQCdcpuAEwGuScVUq0ixT/QAmU7A3/cwlsoxqMkB2XeWYIVTjs7p7Bsu0Ctdid/6pdtP7ghpg==", "dev": true, "requires": { "chalk": "^4.1.0" } }, "@parcel/namer-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.8.3.tgz", - "integrity": "sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/namer-default/-/namer-default-2.9.1.tgz", + "integrity": "sha512-XHpAc5JLQchUqRrYqnUvinReR2nCyiD+DhIedMW5hURwlCPBlfcTVf6M5kSSpjzqRDVKezx3TFF6dzZNv0fBJQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/node-resolver-core": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz", - "integrity": "sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@parcel/node-resolver-core/-/node-resolver-core-3.0.1.tgz", + "integrity": "sha512-4owokOoHCONeazQGndB4PkIaUhZfyWuCT7Sx4UJc2UhR1V82MlahHrT2ItT0pkQyKWwCSNgHdBgdKUgKRdIiAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/utils": "2.8.3", + "@mischnic/json-sourcemap": "^0.1.0", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "semver": "^5.7.1" }, @@ -28827,27 +27980,27 @@ } }, "@parcel/optimizer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz", - "integrity": "sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-css/-/optimizer-css-2.9.1.tgz", + "integrity": "sha512-IYQpV0kc0KN/aqRAWQsZ8b2pbI4ha4T5HAi27lTGIhQNvEixUtf0gJvCJVSlBxpdMiXVJq9pp97UamoNuB6oig==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/optimizer-htmlnano": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz", - "integrity": "sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.9.1.tgz", + "integrity": "sha512-t/e9XsoXZViqOFWcz3LlEClCOYNCjP6MIo+p+WmAuc5+QFF0/9viNqgRbhVe8V1tbtRofxsm4BossFOjOBSjmg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "htmlnano": "^2.0.0", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", @@ -28910,27 +28063,26 @@ } }, "@parcel/optimizer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz", - "integrity": "sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-image/-/optimizer-image-2.9.1.tgz", + "integrity": "sha512-Ml51RUGbQXyoHZ9yhyal8J/khZeWZX5J8NPOEvkCmmOkxo/qM4CMPIvJStzzn5K7mOPRKUheDkM/QoNGO5gTwA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "detect-libc": "^1.0.3" + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1" } }, "@parcel/optimizer-svgo": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz", - "integrity": "sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-svgo/-/optimizer-svgo-2.9.1.tgz", + "integrity": "sha512-8XHSEIjJfdTFtUQzRiy0K+fbvdcheYc+azdyuJPnIV5AX04k4heKwp7uH328Ylk2k0JkfDyQmjFEyPj9qWDadQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "svgo": "^2.4.0" }, "dependencies": { @@ -28989,32 +28141,33 @@ } } }, - "@parcel/optimizer-terser": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz", - "integrity": "sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA==", + "@parcel/optimizer-swc": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/optimizer-swc/-/optimizer-swc-2.9.1.tgz", + "integrity": "sha512-bLDkAwkmFE8YZNHcfJNj22haSLXrqjZkGXbPgGDkanCUS52yWv1+OFZ+6frX2q4EdXaTX8nFZSJL4VPHZZiUGQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "nullthrows": "^1.1.1", - "terser": "^5.2.0" + "@parcel/utils": "2.9.1", + "@swc/core": "^1.3.36", + "nullthrows": "^1.1.1" } }, "@parcel/package-manager": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.8.3.tgz", - "integrity": "sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/package-manager/-/package-manager-2.9.1.tgz", + "integrity": "sha512-cTUBUPRm62770Vw4YG5WGlkFxJII320nSobbP0TMggE/CGXg3ru2pvvX6WqXTFAHeM/z78xTPDq0NP97DBp5Ow==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/node-resolver-core": "3.0.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "semver": "^5.7.1" }, "dependencies": { @@ -29027,49 +28180,50 @@ } }, "@parcel/packager-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.8.3.tgz", - "integrity": "sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-css/-/packager-css-2.9.1.tgz", + "integrity": "sha512-efMShrIwVBY9twZTGQ5QFwl9H3xJg8nSjl/xgOGq9rrbkmcrVlfSgPL9ExNx75EvmOwOKxZjFiMsNYNICPNfgg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/packager-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.8.3.tgz", - "integrity": "sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-html/-/packager-html-2.9.1.tgz", + "integrity": "sha512-mP7iIwyFDZ21XwD2SlwZoSrvKpS5Amlpi/ywd0dLdwQb5TL+Q2f05IcRNfFbWdVd1AJycDQ85ERokNKN3QPMkg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5" } }, "@parcel/packager-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.8.3.tgz", - "integrity": "sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-js/-/packager-js-2.9.1.tgz", + "integrity": "sha512-MmeKdp/obO36M8Y9yYAFiFkdhRFbQtYGSxbMwm2JVtRKMcFmlR5KzqLUg67OX6qgKw5lZZ1TkYhSI0hQQ6+Vqw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "globals": "^13.2.0", "nullthrows": "^1.1.1" }, "dependencies": { "globals": { - "version": "13.19.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.19.0.tgz", - "integrity": "sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==", + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -29078,109 +28232,133 @@ } }, "@parcel/packager-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.8.3.tgz", - "integrity": "sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-raw/-/packager-raw-2.9.1.tgz", + "integrity": "sha512-qHJ389R5cLgR2PcJt8sOrNBcAY0qpZRMTOMgkc9zYkKy1tdUMgCUuDfO1kShfv4E7rr084mtlu9tK8MXChyF6w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/packager-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.8.3.tgz", - "integrity": "sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/packager-svg/-/packager-svg-2.9.1.tgz", + "integrity": "sha512-aRzuiwcUlNATfSIbeYpDkJXvwdiAAbiQlxSz6cI53NqWwZn+Dn79WyiKPBST14ij4/P3ZjkcwXevqHpvXP/ArQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "posthtml": "^0.16.4" } }, "@parcel/plugin": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.8.3.tgz", - "integrity": "sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/plugin/-/plugin-2.9.1.tgz", + "integrity": "sha512-kD+BNkPGRcxZZUKhAXqF/bilUMhXUlf/ZixVlBS5rEsUB1yx/Ze8c4ypaKr5WsEwv34C+X4p4WFYdZVJEr3Y+g==", "dev": true, "requires": { - "@parcel/types": "2.8.3" + "@parcel/types": "2.9.1" + } + }, + "@parcel/profiler": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/profiler/-/profiler-2.9.1.tgz", + "integrity": "sha512-hrptwbh9uUxnWHAAXiZ6BtpM74cU+VfrOWgnmUA8pkYWBmrb2wSLeqRKl8FiSt+nfRTTbNAIlmn9vk2x+wRNOA==", + "dev": true, + "requires": { + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "chrome-trace-event": "^1.0.2" } }, "@parcel/reporter-cli": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz", - "integrity": "sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-cli/-/reporter-cli-2.9.1.tgz", + "integrity": "sha512-xzJaaHQwcsmHijlCl7gOAdqU0n6AnW7c7rN8AXDH8BvnOx2v8NC8nCIEmDTOfpQYepcuER2+ilTQ7jpDx/iDhg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "term-size": "^2.2.1" } }, "@parcel/reporter-dev-server": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz", - "integrity": "sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-dev-server/-/reporter-dev-server-2.9.1.tgz", + "integrity": "sha512-Wa9kmtnuYTqEsKakhrSLvZmWxM4TB+Dg2jl1vC3gYfvlsgt/d/Hp/y2giPH1EeCm4wEEQfdAY3WmSUx9p1x07w==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" + } + }, + "@parcel/reporter-tracer": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/reporter-tracer/-/reporter-tracer-2.9.1.tgz", + "integrity": "sha512-LgZKx9qwBAChWHBcpHW8GJXz45IGtiPmzs6HIDavZOiGqjGVzmbHUKxHnFaRZqR6WznJ+0ay/2o+BrJ8cyXUcg==", + "dev": true, + "requires": { + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "chrome-trace-event": "^1.0.3", + "nullthrows": "^1.1.1" } }, "@parcel/resolver-default": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.8.3.tgz", - "integrity": "sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/resolver-default/-/resolver-default-2.9.1.tgz", + "integrity": "sha512-Q+knNaRDTbGIGqUnddtWEgpYduVBkDyi/CpxKpi7dP7sVYNJsXwEf82hpjX6/XqotA5dehT63yJkvJ/wxJF1Nw==", "dev": true, "requires": { - "@parcel/node-resolver-core": "2.8.3", - "@parcel/plugin": "2.8.3" + "@parcel/node-resolver-core": "3.0.1", + "@parcel/plugin": "2.9.1" } }, "@parcel/runtime-browser-hmr": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz", - "integrity": "sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.9.1.tgz", + "integrity": "sha512-C+023FOsrycpBHUgUf7Nv4uN0NrLN3UkeymsAHQlgZD5QQD7+nhG6p9PQ7+HbbEAaGaeO7c/86s2qRUglufNig==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3" + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1" } }, "@parcel/runtime-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.8.3.tgz", - "integrity": "sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-js/-/runtime-js-2.9.1.tgz", + "integrity": "sha512-caT1s1BqYNFGFAz9ul7uwDf+ZXzipiYYoHphhmT2JFweQmRA1CrMeFCuCQa2exsdu+UQpRbuKd+v5UUS2n0poQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/runtime-react-refresh": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz", - "integrity": "sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.9.1.tgz", + "integrity": "sha512-opDW9p3f4gVc1aVdFAyLWTL+2S8rhsPdBQRBHEi4WE2DRe/9lpA12NN5KUUHy88dlIr3wyzmaO2Fts0r/x80zg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-error-overlay": "6.0.9", "react-refresh": "^0.9.0" } }, "@parcel/runtime-service-worker": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz", - "integrity": "sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/runtime-service-worker/-/runtime-service-worker-2.9.1.tgz", + "integrity": "sha512-TED4MouYjP7xbU9V7/3rjnmuWbCefrP+OC+eQJG6j3HwKiL92QTZ6trWqdLuxFhtZMXKjwbWaBBbIcELB/PbtQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -29194,15 +28372,15 @@ } }, "@parcel/transformer-babel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz", - "integrity": "sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-babel/-/transformer-babel-2.9.1.tgz", + "integrity": "sha512-HEU3bavD9Cu0RP5T1ioGLbsOQDqND/SQWal8L2f9HsgwTs2kzmTxYylNccqNjAMj3NnoyXzKMKbZyG8qEuLlpw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "json5": "^2.2.0", "nullthrows": "^1.1.1", @@ -29218,29 +28396,29 @@ } }, "@parcel/transformer-css": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.8.3.tgz", - "integrity": "sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-css/-/transformer-css-2.9.1.tgz", + "integrity": "sha512-nT+xOfyveX6qSb088dOh59HWJ1gm7DAIQZPbjTa1wLzRQul8ysdQRf/loulBmtUheol7YwQtVvUHN2XgoMDCAw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", + "@parcel/utils": "2.9.1", "browserslist": "^4.6.6", "lightningcss": "^1.16.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-html": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.8.3.tgz", - "integrity": "sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-html/-/transformer-html-2.9.1.tgz", + "integrity": "sha512-pIkJbcB91Dl2RyZmVd9neGkf7XJeYXwgx0et5hktw+3m0S2QB399OjVWwi5Q6ZdtTrWkQnHLmbeHT3NOmNWlaw==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -29258,45 +28436,35 @@ } }, "@parcel/transformer-image": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.8.3.tgz", - "integrity": "sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-image/-/transformer-image-2.9.1.tgz", + "integrity": "sha512-3D4zEavCM1i354ZgJWg7RBNgASA7Q2iHN374lH5hT6I7VAJzNT+PTNrPNQ4vKhi69r+i1sQQzsPdgEUXOExmbQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", "nullthrows": "^1.1.1" } }, "@parcel/transformer-js": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.8.3.tgz", - "integrity": "sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-js/-/transformer-js-2.9.1.tgz", + "integrity": "sha512-7hlbAIufIvx6iPspfZ3v1g2cmtpaNEaC04RzRv8HVVru8TE868yplFI840ZBnF5ylOfmxwFTUjlphVtVcPs13A==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/plugin": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/utils": "2.8.3", - "@parcel/workers": "2.8.3", - "@swc/helpers": "^0.4.12", + "@parcel/utils": "2.9.1", + "@parcel/workers": "2.9.1", + "@swc/helpers": "^0.5.0", "browserslist": "^4.6.6", - "detect-libc": "^1.0.3", "nullthrows": "^1.1.1", "regenerator-runtime": "^0.13.7", "semver": "^5.7.1" }, "dependencies": { - "@swc/helpers": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.14.tgz", - "integrity": "sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==", - "dev": true, - "requires": { - "tslib": "^2.4.0" - } - }, "semver": { "version": "5.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", @@ -29306,25 +28474,25 @@ } }, "@parcel/transformer-json": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.8.3.tgz", - "integrity": "sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-json/-/transformer-json-2.9.1.tgz", + "integrity": "sha512-yFRSz1qVbdCssC65D37Ru3diQk7GQl5ZOOyQ7MeMYlhvl8mcFKGRC3wUAyqBZrh70VOWuWR7WS2XLdqTdE9WqQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", + "@parcel/plugin": "2.9.1", "json5": "^2.2.0" } }, "@parcel/transformer-postcss": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz", - "integrity": "sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-postcss/-/transformer-postcss-2.9.1.tgz", + "integrity": "sha512-sNSJbdT4Z8H+/cZ/vCmos44SfbB9O5gNgMEgGa6WqU7MV7cVlnE8zuNJkxR97ZZTpIXNrfVerOY3lOrUrFCxdA==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "clone": "^2.1.1", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", @@ -29340,13 +28508,13 @@ } }, "@parcel/transformer-posthtml": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz", - "integrity": "sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-posthtml/-/transformer-posthtml-2.9.1.tgz", + "integrity": "sha512-I6fr6lVAqjDxdkOwxelx7FibMWP55JPf3ZTXKCWpoIGkOuT2i2tYZMdXEHVshZWJmByelbYSC96w8P8rSY+6XQ==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -29363,34 +28531,34 @@ } }, "@parcel/transformer-raw": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz", - "integrity": "sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-raw/-/transformer-raw-2.9.1.tgz", + "integrity": "sha512-Wr0Y9fETiyF5ntL3yhn/ZXjcnswcn1T9YLXa+yAxpAxKW+/D7A1jKVS0tyDOZsdakWA9gzlLP6w1O4Nl8pVmEg==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3" + "@parcel/plugin": "2.9.1" } }, "@parcel/transformer-react-refresh-wrap": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz", - "integrity": "sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.9.1.tgz", + "integrity": "sha512-ML+KDvLoZ6O+9r3/yf8DeVtobhYc9DPXYHZ75aXoFyou97I9WDf4EqlY4/MSkbZV79FUXxC68dyLJj3Q9ILqeA==", "dev": true, "requires": { - "@parcel/plugin": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/plugin": "2.9.1", + "@parcel/utils": "2.9.1", "react-refresh": "^0.9.0" } }, "@parcel/transformer-svg": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz", - "integrity": "sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/transformer-svg/-/transformer-svg-2.9.1.tgz", + "integrity": "sha512-DYcUfutjtghPXMVybFygncIKJl/4rrpQMxv8yTVeDtplUTvFzbI+3hIoYfYm8z9CXaSBzsCw2Kud6PD8Ob2AzQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/plugin": "2.8.3", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/plugin": "2.9.1", "nullthrows": "^1.1.1", "posthtml": "^0.16.5", "posthtml-parser": "^0.10.1", @@ -29407,33 +28575,34 @@ } }, "@parcel/types": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.8.3.tgz", - "integrity": "sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/types/-/types-2.9.1.tgz", + "integrity": "sha512-LBx4Tvr1sK9t+FmPjS4jPvcmUcJo6co22sn0pBuz2oXISs/YK2N+3ZHXL+KsozKvLn2wXysgaWFIARN9xFoORw==", "dev": true, "requires": { - "@parcel/cache": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/package-manager": "2.8.3", + "@parcel/cache": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/package-manager": "2.9.1", "@parcel/source-map": "^2.1.1", - "@parcel/workers": "2.8.3", + "@parcel/workers": "2.9.1", "utility-types": "^3.10.0" } }, "@parcel/utils": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.8.3.tgz", - "integrity": "sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/utils/-/utils-2.9.1.tgz", + "integrity": "sha512-0P/zIvtvLyuzQA4VFMzA8F22lrUyGR+phve/NlBUH+4Tn+Rt/evh9fP9vG1YTVMXWd90tesLdrtqatm1hqrJSA==", "dev": true, "requires": { - "@parcel/codeframe": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/hash": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/markdown-ansi": "2.8.3", + "@parcel/codeframe": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/hash": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/markdown-ansi": "2.9.1", "@parcel/source-map": "^2.1.1", - "chalk": "^4.1.0" + "chalk": "^4.1.0", + "nullthrows": "^1.1.1" } }, "@parcel/watcher": { @@ -29449,16 +28618,16 @@ } }, "@parcel/workers": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.8.3.tgz", - "integrity": "sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/@parcel/workers/-/workers-2.9.1.tgz", + "integrity": "sha512-24R4IRMX8TBghak6pDCzM5B8NB4LTt0pI4dwNqSENyZA/Q5s/xMbG5gdn4aTwkAyIQ5lHrgDsHzoHbjOT0HLYQ==", "dev": true, "requires": { - "@parcel/diagnostic": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/types": "2.8.3", - "@parcel/utils": "2.8.3", - "chrome-trace-event": "^1.0.2", + "@parcel/diagnostic": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/profiler": "2.9.1", + "@parcel/types": "2.9.1", + "@parcel/utils": "2.9.1", "nullthrows": "^1.1.1" } }, @@ -29619,8 +28788,6 @@ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz", "integrity": "sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg==", "dev": true, - "optional": true, - "peer": true, "requires": { "tslib": "^2.4.0" } @@ -29665,7 +28832,7 @@ "@tailwindcss/integrations-parcel": { "version": "file:integrations/parcel", "requires": { - "parcel": "^2.8.3" + "parcel": "2.9.1" } }, "@tailwindcss/integrations-postcss-cli": { @@ -31926,16 +31093,16 @@ } }, "domutils": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.0.1.tgz", - "integrity": "sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", "dev": true, "optional": true, "peer": true, "requires": { "dom-serializer": "^2.0.0", "domelementtype": "^2.3.0", - "domhandler": "^5.0.1" + "domhandler": "^5.0.3" } }, "entities": { @@ -31969,80 +31136,6 @@ "cssesc": { "version": "3.0.0" }, - "cssnano": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.1.tgz", - "integrity": "sha512-fVO1JdJ0LSdIGJq68eIxOqFpIJrZqXUsBt8fkrBcztCQqAjQD51OhZp7tc0ImcbwXD4k7ny84QTV90nZhmqbkg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "cssnano-preset-default": "^6.0.1", - "lilconfig": "^2.1.0" - } - }, - "cssnano-preset-default": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.1.tgz", - "integrity": "sha512-7VzyFZ5zEB1+l1nToKyrRkuaJIx0zi/1npjvZfbBwbtNTzhLtlvYraK/7/uqmX2Wb2aQtd983uuGw79jAjLSuQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "css-declaration-sorter": "^6.3.1", - "cssnano-utils": "^4.0.0", - "postcss-calc": "^9.0.0", - "postcss-colormin": "^6.0.0", - "postcss-convert-values": "^6.0.0", - "postcss-discard-comments": "^6.0.0", - "postcss-discard-duplicates": "^6.0.0", - "postcss-discard-empty": "^6.0.0", - "postcss-discard-overridden": "^6.0.0", - "postcss-merge-longhand": "^6.0.0", - "postcss-merge-rules": "^6.0.1", - "postcss-minify-font-values": "^6.0.0", - "postcss-minify-gradients": "^6.0.0", - "postcss-minify-params": "^6.0.0", - "postcss-minify-selectors": "^6.0.0", - "postcss-normalize-charset": "^6.0.0", - "postcss-normalize-display-values": "^6.0.0", - "postcss-normalize-positions": "^6.0.0", - "postcss-normalize-repeat-style": "^6.0.0", - "postcss-normalize-string": "^6.0.0", - "postcss-normalize-timing-functions": "^6.0.0", - "postcss-normalize-unicode": "^6.0.0", - "postcss-normalize-url": "^6.0.0", - "postcss-normalize-whitespace": "^6.0.0", - "postcss-ordered-values": "^6.0.0", - "postcss-reduce-initial": "^6.0.0", - "postcss-reduce-transforms": "^6.0.0", - "postcss-svgo": "^6.0.0", - "postcss-unique-selectors": "^6.0.0" - }, - "dependencies": { - "postcss-calc": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", - "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-selector-parser": "^6.0.11", - "postcss-value-parser": "^4.2.0" - } - } - } - }, - "cssnano-utils": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.0.tgz", - "integrity": "sha512-Z39TLP+1E0KUcd7LGyF4qMfu8ZufI0rDzhdyAMsa/8UyNUU8wpS0fhdBxbQbv32r64ea00h4878gommRVg2BHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, "csso": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", @@ -32231,11 +31324,21 @@ }, "dom-serializer": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dev": true, "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", "entities": "^2.0.0" + }, + "dependencies": { + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + } } }, "domain-browser": { @@ -32246,10 +31349,14 @@ }, "domelementtype": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, "domhandler": { "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dev": true, "requires": { "domelementtype": "^2.2.0" @@ -32257,6 +31364,8 @@ }, "domutils": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", "dev": true, "requires": { "dom-serializer": "^1.0.1", @@ -32352,7 +31461,9 @@ } }, "entities": { - "version": "2.2.0", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", + "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", "dev": true }, "envinfo": { @@ -33468,14 +32579,6 @@ "domhandler": "^4.2.2", "domutils": "^2.8.0", "entities": "^3.0.1" - }, - "dependencies": { - "entities": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz", - "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==", - "dev": true - } } }, "http-cache-semantics": { @@ -34870,24 +33973,33 @@ "version": "1.2.4" }, "lmdb": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.5.2.tgz", - "integrity": "sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA==", + "version": "2.7.11", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-2.7.11.tgz", + "integrity": "sha512-x9bD4hVp7PFLUoELL8RglbNXhAMt5CYhkmss+CEau9KlNoilsTzNi9QDsPZb3KMpOGZXG6jmXhW3bBxE2XVztw==", "dev": true, "requires": { - "@lmdb/lmdb-darwin-arm64": "2.5.2", - "@lmdb/lmdb-darwin-x64": "2.5.2", - "@lmdb/lmdb-linux-arm": "2.5.2", - "@lmdb/lmdb-linux-arm64": "2.5.2", - "@lmdb/lmdb-linux-x64": "2.5.2", - "@lmdb/lmdb-win32-x64": "2.5.2", - "msgpackr": "^1.5.4", + "@lmdb/lmdb-darwin-arm64": "2.7.11", + "@lmdb/lmdb-darwin-x64": "2.7.11", + "@lmdb/lmdb-linux-arm": "2.7.11", + "@lmdb/lmdb-linux-arm64": "2.7.11", + "@lmdb/lmdb-linux-x64": "2.7.11", + "@lmdb/lmdb-win32-x64": "2.7.11", + "msgpackr": "1.8.5", "node-addon-api": "^4.3.0", - "node-gyp-build-optional-packages": "5.0.3", - "ordered-binary": "^1.2.4", + "node-gyp-build-optional-packages": "5.0.6", + "ordered-binary": "^1.4.0", "weak-lru-cache": "^1.2.2" }, "dependencies": { + "msgpackr": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.5.tgz", + "integrity": "sha512-mpPs3qqTug6ahbblkThoUY2DQdNXcm4IapwOS3Vm/87vmpzLVelvp9h3It1y9l1VPpiFLV11vfOXnmeEwiIXwg==", + "dev": true, + "requires": { + "msgpackr-extract": "^3.0.1" + } + }, "node-addon-api": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", @@ -35241,28 +34353,37 @@ "dev": true }, "msgpackr": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.8.2.tgz", - "integrity": "sha512-eLuPeok0DMwsGN23AvuVg32mYpx55tsQnxI87d8V1yZsdT8U5jrWhmCa1INO/joGAFQFfo/eTlM/BxVwLKbBOQ==", + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.9.2.tgz", + "integrity": "sha512-xtDgI3Xv0AAiZWLRGDchyzBwU6aq0rwJ+W+5Y4CZhEWtkl/hJtFFLc+3JtGTw7nz1yquxs7nL8q/yA2aqpflIQ==", "dev": true, "requires": { - "msgpackr-extract": "^2.2.0" + "msgpackr-extract": "^3.0.2" } }, "msgpackr-extract": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-2.2.0.tgz", - "integrity": "sha512-0YcvWSv7ZOGl9Od6Y5iJ3XnPww8O7WLcpYMDwX+PAA/uXLDtyw94PJv9GLQV/nnp3cWlDhMoyKZIQLrx33sWog==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", + "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", "dev": true, "optional": true, "requires": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-linux-x64": "2.2.0", - "@msgpackr-extract/msgpackr-extract-win32-x64": "2.2.0", - "node-gyp-build-optional-packages": "5.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2", + "node-gyp-build-optional-packages": "5.0.7" + }, + "dependencies": { + "node-gyp-build-optional-packages": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", + "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "dev": true, + "optional": true + } } }, "mz": { @@ -35338,9 +34459,9 @@ "dev": true }, "node-gyp-build-optional-packages": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz", - "integrity": "sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.6.tgz", + "integrity": "sha512-2ZJErHG4du9G3/8IWl/l9Bp5BBFy63rno5GVmjQijvTuUZKsl6g8RB4KH/x3NLcV5ZBb4GsXmAuTYr6dRml3Gw==", "dev": true }, "node-int64": { @@ -35664,25 +34785,25 @@ } }, "parcel": { - "version": "2.8.3", - "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.8.3.tgz", - "integrity": "sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA==", + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/parcel/-/parcel-2.9.1.tgz", + "integrity": "sha512-LBD+jeCpvnDJ8MeE0ciEns4EZw+WH01qLEKT2O1tW2uHM1njhcWvuc9bx19f8iyE2+8Xwwr2GsGTQgPXKiA/yQ==", "dev": true, "requires": { - "@parcel/config-default": "2.8.3", - "@parcel/core": "2.8.3", - "@parcel/diagnostic": "2.8.3", - "@parcel/events": "2.8.3", - "@parcel/fs": "2.8.3", - "@parcel/logger": "2.8.3", - "@parcel/package-manager": "2.8.3", - "@parcel/reporter-cli": "2.8.3", - "@parcel/reporter-dev-server": "2.8.3", - "@parcel/utils": "2.8.3", + "@parcel/config-default": "2.9.1", + "@parcel/core": "2.9.1", + "@parcel/diagnostic": "2.9.1", + "@parcel/events": "2.9.1", + "@parcel/fs": "2.9.1", + "@parcel/logger": "2.9.1", + "@parcel/package-manager": "2.9.1", + "@parcel/reporter-cli": "2.9.1", + "@parcel/reporter-dev-server": "2.9.1", + "@parcel/reporter-tracer": "2.9.1", + "@parcel/utils": "2.9.1", "chalk": "^4.1.0", "commander": "^7.0.0", - "get-port": "^4.2.0", - "v8-compile-cache": "^2.0.0" + "get-port": "^4.2.0" } }, "parent-module": { @@ -35866,68 +34987,6 @@ } } }, - "postcss-colormin": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.0.tgz", - "integrity": "sha512-EuO+bAUmutWoZYgHn2T1dG1pPqHU6L4TjzPlu4t1wZGXQ/fxV16xg2EJmYi0z+6r+MGV1yvpx1BHkUaRrPa2bw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "colord": "^2.9.1", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-convert-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.0.tgz", - "integrity": "sha512-U5D8QhVwqT++ecmy8rnTb+RL9n/B806UVaS3m60lqle4YDFcpbS3ae5bTQIh3wOGUSDHSEtMYLs/38dNG7EYFw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-discard-comments": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.0.tgz", - "integrity": "sha512-p2skSGqzPMZkEQvJsgnkBhCn8gI7NzRH2683EEjrIkoMiwRELx68yoUJ3q3DGSGuQ8Ug9Gsn+OuDr46yfO+eFw==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-discard-duplicates": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.0.tgz", - "integrity": "sha512-bU1SXIizMLtDW4oSsi5C/xHKbhLlhek/0/yCnoMQany9k3nPBq+Ctsv/9oMmyqbR96HYHxZcHyK2HR5P/mqoGA==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-discard-empty": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.0.tgz", - "integrity": "sha512-b+h1S1VT6dNhpcg+LpyiUrdnEZfICF0my7HAKgJixJLW7BnNmpRH34+uw/etf5AhOlIhIAuXApSzzDzMI9K/gQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-discard-overridden": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.0.tgz", - "integrity": "sha512-4VELwssYXDFigPYAZ8vL4yX4mUepF/oCBeeIT4OXsJPYOtvJumyz9WflmJWTfDwCUcpDR+z0zvCWBXgTx35SVw==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, "postcss-import": { "version": "15.1.0", "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", @@ -35997,80 +35056,6 @@ } } }, - "postcss-merge-longhand": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.0.tgz", - "integrity": "sha512-4VSfd1lvGkLTLYcxFuISDtWUfFS4zXe0FpF149AyziftPFQIWxjvFSKhA4MIxMe4XM3yTDgQMbSNgzIVxChbIg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "stylehacks": "^6.0.0" - } - }, - "postcss-merge-rules": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.1.tgz", - "integrity": "sha512-a4tlmJIQo9SCjcfiCcCMg/ZCEe0XTkl/xK0XHBs955GWg9xDX3NwP9pwZ78QUOWB8/0XCjZeJn98Dae0zg6AAw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0", - "cssnano-utils": "^4.0.0", - "postcss-selector-parser": "^6.0.5" - } - }, - "postcss-minify-font-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.0.tgz", - "integrity": "sha512-zNRAVtyh5E8ndZEYXA4WS8ZYsAp798HiIQ1V2UF/C/munLp2r1UGHwf1+6JFu7hdEhJFN+W1WJQKBrtjhFgEnA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-gradients": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.0.tgz", - "integrity": "sha512-wO0F6YfVAR+K1xVxF53ueZJza3L+R3E6cp0VwuXJQejnNUH0DjcAFe3JEBeTY1dLwGa0NlDWueCA1VlEfiKgAA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "colord": "^2.9.1", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-params": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.0.tgz", - "integrity": "sha512-Fz/wMQDveiS0n5JPcvsMeyNXOIMrwF88n7196puSuQSWSa+/Ofc1gDOSY2xi8+A4PqB5dlYCKk/WfqKqsI+ReQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-minify-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.0.tgz", - "integrity": "sha512-ec/q9JNCOC2CRDNnypipGfOhbYPuUkewGwLnbv6omue/PSASbHSU7s6uSQ0tcFRVv731oMIx8k0SP4ZX6be/0g==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-modules": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-4.3.1.tgz", @@ -36131,139 +35116,6 @@ "postcss-selector-parser": "^6.0.11" } }, - "postcss-normalize-charset": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.0.tgz", - "integrity": "sha512-cqundwChbu8yO/gSWkuFDmKrCZ2vJzDAocheT2JTd0sFNA4HMGoKMfbk2B+J0OmO0t5GUkiAkSM5yF2rSLUjgQ==", - "dev": true, - "optional": true, - "peer": true, - "requires": {} - }, - "postcss-normalize-display-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.0.tgz", - "integrity": "sha512-Qyt5kMrvy7dJRO3OjF7zkotGfuYALETZE+4lk66sziWSPzlBEt7FrUshV6VLECkI4EN8Z863O6Nci4NXQGNzYw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-positions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.0.tgz", - "integrity": "sha512-mPCzhSV8+30FZyWhxi6UoVRYd3ZBJgTRly4hOkaSifo0H+pjDYcii/aVT4YE6QpOil15a5uiv6ftnY3rm0igPg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-repeat-style": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.0.tgz", - "integrity": "sha512-50W5JWEBiOOAez2AKBh4kRFm2uhrT3O1Uwdxz7k24aKtbD83vqmcVG7zoIwo6xI2FZ/HDlbrCopXhLeTpQib1A==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-string": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.0.tgz", - "integrity": "sha512-KWkIB7TrPOiqb8ZZz6homet2KWKJwIlysF5ICPZrXAylGe2hzX/HSf4NTX2rRPJMAtlRsj/yfkrWGavFuB+c0w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-timing-functions": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.0.tgz", - "integrity": "sha512-tpIXWciXBp5CiFs8sem90IWlw76FV4oi6QEWfQwyeREVwUy39VSeSqjAT7X0Qw650yAimYW5gkl2Gd871N5SQg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-unicode": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.0.tgz", - "integrity": "sha512-ui5crYkb5ubEUDugDc786L/Me+DXp2dLg3fVJbqyAl0VPkAeALyAijF2zOsnZyaS1HyfPuMH0DwyY18VMFVNkg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-url": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.0.tgz", - "integrity": "sha512-98mvh2QzIPbb02YDIrYvAg4OUzGH7s1ZgHlD3fIdTHLgPLRpv1ZTKJDnSAKr4Rt21ZQFzwhGMXxpXlfrUBKFHw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-normalize-whitespace": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.0.tgz", - "integrity": "sha512-7cfE1AyLiK0+ZBG6FmLziJzqQCpTQY+8XjMhMAz8WSBSCsCNNUKujgIgjCAmDT3cJ+3zjTXFkoD15ZPsckArVw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-ordered-values": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.0.tgz", - "integrity": "sha512-K36XzUDpvfG/nWkjs6d1hRBydeIxGpKS2+n+ywlKPzx1nMYDYpoGbcjhj5AwVYJK1qV2/SDoDEnHzlPD6s3nMg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "cssnano-utils": "^4.0.0", - "postcss-value-parser": "^4.2.0" - } - }, - "postcss-reduce-initial": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.0.tgz", - "integrity": "sha512-s2UOnidpVuXu6JiiI5U+fV2jamAw5YNA9Fdi/GRK0zLDLCfXmSGqQtzpUPtfN66RtCbb9fFHoyZdQaxOB3WxVA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "caniuse-api": "^3.0.0" - } - }, - "postcss-reduce-transforms": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.0.tgz", - "integrity": "sha512-FQ9f6xM1homnuy1wLe9lP1wujzxnwt1EwiigtWwuyf8FsqqXUDUp2Ulxf9A5yjlUOTdCJO6lonYjg1mgqIIi2w==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0" - } - }, "postcss-reporter": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-7.0.5.tgz", @@ -36283,29 +35135,6 @@ "util-deprecate": "^1.0.2" } }, - "postcss-svgo": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.0.tgz", - "integrity": "sha512-r9zvj/wGAoAIodn84dR/kFqwhINp5YsJkLoujybWG59grR/IHx+uQ2Zo+IcOwM0jskfYX3R0mo+1Kip1VSNcvw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-value-parser": "^4.2.0", - "svgo": "^3.0.2" - } - }, - "postcss-unique-selectors": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.0.tgz", - "integrity": "sha512-EPQzpZNxOxP7777t73RQpZE5e9TrnCrkvp7AH7a0l89JmZiPnS82y216JowHXwpBCQitfyxrof9TK3rYbi7/Yw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "postcss-selector-parser": "^6.0.5" - } - }, "postcss-value-parser": { "version": "4.2.0" }, @@ -37842,18 +36671,6 @@ "integrity": "sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==", "dev": true }, - "stylehacks": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.0.tgz", - "integrity": "sha512-+UT589qhHPwz6mTlCLSt/vMNTJx8dopeJlZAlBMJPWA3ORqu6wmQY7FBXf+qD+FsqoBJODyqNxOUP3jdntFRdw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "browserslist": "^4.21.4", - "postcss-selector-parser": "^6.0.4" - } - }, "sucrase": { "version": "3.32.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.32.0.tgz", @@ -38443,12 +37260,6 @@ "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", "dev": true }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -39639,12 +38450,6 @@ "integrity": "sha512-O11mqxmi7wMKCo6HKFt5AhO4BwY3VV68YU07tgxfz8zJTIxr4BpsezN49Ffwy9j3ZpwwJp4fkRwjRzq3uWE6Rg==", "dev": true }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, "v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", From b05b617601f577b31305358a3f96c767558274d4 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 2 Jun 2023 15:24:40 +0200 Subject: [PATCH 46/85] Bump Rust version to 1.70.0 (#11344) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * `cargo clippy --fix` * use `map_while` instead of `filter_map` - `filter_map()` will run forever if the iterator repeatedly produces an `Err` ``` ❯ cargo clippy Checking tailwindcss-oxide v0.1.0 (/Users/robin/github.com/tailwindlabs/tailwindcss/oxide/crates/cli) warning: `filter_map()` will run forever if the iterator repeatedly produces an `Err` --> crates/cli/src/main.rs:108:14 | 108 | .filter_map(Result::ok) | ^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `map_while(Result::ok)` | note: this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error --> crates/cli/src/main.rs:106:9 | 106 | / read_lines(path) 107 | | .unwrap() | |_____________________^ = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#lines_filter_map_ok = note: `#[warn(clippy::lines_filter_map_ok)]` on by default warning: `tailwindcss-oxide` (bin "tailwindcss-oxide") generated 1 warning Finished dev [unoptimized + debuginfo] target(s) in 0.13s ``` * log used versions of all the tools we are using * ensure we install Rust --- .github/workflows/ci.yml | 14 ++++++++++++++ .github/workflows/integration-tests.yml | 14 ++++++++++++++ .github/workflows/prepare-release.yml | 14 ++++++++++++++ oxide/crates/cli/src/main.rs | 2 +- .../crates/core/benches/parse_candidate_strings.rs | 1 - oxide/crates/core/src/candidate.rs | 1 - oxide/crates/core/src/glob.rs | 1 - oxide/crates/core/src/lib.rs | 4 ++-- oxide/crates/core/src/parser.rs | 4 ++-- 9 files changed, 47 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5488096e3..0241a67b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,6 +61,20 @@ jobs: - name: Install dependencies run: npm install + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Check versions + run: | + echo "Node:" `node --version` + echo "NPM:" `npm --version` + echo "Rust:" `rustc --version` + echo "Cargo:" `cargo --version` + - name: Build Tailwind CSS run: npx turbo run build --filter=// diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 722a08ad3..3fd0f3f33 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -73,6 +73,20 @@ jobs: - name: Install dependencies run: npm install + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Check versions + run: | + echo "Node:" `node --version` + echo "NPM:" `npm --version` + echo "Rust:" `rustc --version` + echo "Cargo:" `cargo --version` + - name: Build Tailwind CSS run: npx turbo run build --filter=// diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 2ad36d3dd..af5ef0be7 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -53,6 +53,20 @@ jobs: - name: Install dependencies run: npm install + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: stable + profile: minimal + override: true + + - name: Check versions + run: | + echo "Node:" `node --version` + echo "NPM:" `npm --version` + echo "Rust:" `rustc --version` + echo "Cargo:" `cargo --version` + - name: Build Tailwind CSS run: npm run build diff --git a/oxide/crates/cli/src/main.rs b/oxide/crates/cli/src/main.rs index cda7c48aa..767d440ae 100644 --- a/oxide/crates/cli/src/main.rs +++ b/oxide/crates/cli/src/main.rs @@ -105,7 +105,7 @@ fn main() -> Result<(), std::io::Error> { let candidates = content_paths.par_bridge().flat_map(|path| { read_lines(path) .unwrap() - .filter_map(Result::ok) + .map_while(Result::ok) .par_bridge() .flat_map_iter(|line| { Extractor::unique(line.as_bytes(), Default::default()) diff --git a/oxide/crates/core/benches/parse_candidate_strings.rs b/oxide/crates/core/benches/parse_candidate_strings.rs index 7db451000..16672f058 100644 --- a/oxide/crates/core/benches/parse_candidate_strings.rs +++ b/oxide/crates/core/benches/parse_candidate_strings.rs @@ -11,7 +11,6 @@ pub fn criterion_benchmark(c: &mut Criterion) { let mut all_files: Vec<(u64, PathBuf)> = std::fs::read_dir(fixtures_path) .unwrap() - .into_iter() .filter_map(Result::ok) .map(|dir_entry| dir_entry.path()) .filter(|path| path.is_file()) diff --git a/oxide/crates/core/src/candidate.rs b/oxide/crates/core/src/candidate.rs index b77ace8b2..3a608a152 100644 --- a/oxide/crates/core/src/candidate.rs +++ b/oxide/crates/core/src/candidate.rs @@ -22,7 +22,6 @@ impl Candidate { x == ':' && !in_arbitrary } }) - .into_iter() .collect::>(); let utility = match parts.pop() { diff --git a/oxide/crates/core/src/glob.rs b/oxide/crates/core/src/glob.rs index f9e355075..f0ed8ab71 100644 --- a/oxide/crates/core/src/glob.rs +++ b/oxide/crates/core/src/glob.rs @@ -12,7 +12,6 @@ pub fn fast_glob( .follow_links(true) .build() .unwrap() - .into_iter() .filter_map(Result::ok) .map(|file| file.path().to_path_buf()) })) diff --git a/oxide/crates/core/src/lib.rs b/oxide/crates/core/src/lib.rs index 6d6202895..858e17a2d 100644 --- a/oxide/crates/core/src/lib.rs +++ b/oxide/crates/core/src/lib.rs @@ -43,7 +43,7 @@ pub fn resolve_content_paths(args: ContentPathInfo) -> Vec { let root = Path::new(&args.base); let allowed_paths = FxHashSet::from_iter( - WalkBuilder::new(&root) + WalkBuilder::new(root) .hidden(false) .filter_entry(|entry| match entry.file_type() { Some(file_type) if file_type.is_dir() => entry @@ -94,7 +94,7 @@ pub fn resolve_content_paths(args: ContentPathInfo) -> Vec { // Collect all valid paths from the root. This will already filter out ignored files, unknown // extensions and binary files. - let mut it = WalkDir::new(&root) + let mut it = WalkDir::new(root) // Sorting to make sure that we always see the directories before the files. Also sorting // alphabetically by default. .sort_by( diff --git a/oxide/crates/core/src/parser.rs b/oxide/crates/core/src/parser.rs index 372758e8e..acee57022 100644 --- a/oxide/crates/core/src/parser.rs +++ b/oxide/crates/core/src/parser.rs @@ -31,13 +31,13 @@ pub struct Extractor<'a> { impl<'a> Extractor<'a> { pub fn all(input: &'a [u8], opts: ExtractorOptions) -> Vec<&'a [u8]> { - Self::new(input, opts).into_iter().collect() + Self::new(input, opts).collect() } pub fn unique(input: &'a [u8], opts: ExtractorOptions) -> FxHashSet<&'a [u8]> { let mut candidates: FxHashSet<&[u8]> = Default::default(); candidates.reserve(100); - candidates.extend(Self::new(input, opts).into_iter()); + candidates.extend(Self::new(input, opts)); candidates } From 729dafeb82ffdf81841e7f8fc919b47697e3f80c Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Sun, 4 Jun 2023 09:55:54 +0000 Subject: [PATCH 47/85] Update postcss to version 8.4.24 --- integrations/content-resolution/package.json | 2 +- integrations/postcss-cli/package.json | 2 +- package-lock.json | 38 ++++++++++---------- package.json | 2 +- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/integrations/content-resolution/package.json b/integrations/content-resolution/package.json index 5587595d7..1e17085de 100644 --- a/integrations/content-resolution/package.json +++ b/integrations/content-resolution/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } } diff --git a/integrations/postcss-cli/package.json b/integrations/postcss-cli/package.json index 07967231d..337ec0d26 100644 --- a/integrations/postcss-cli/package.json +++ b/integrations/postcss-cli/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } } diff --git a/package-lock.json b/package-lock.json index 0a07642b3..10d5e7c3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -30,7 +30,7 @@ "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", @@ -68,7 +68,7 @@ "name": "@tailwindcss/integrations-content-resolution", "version": "0.0.0", "devDependencies": { - "postcss": "^8.4.23", + "postcss": "8.4.24", "postcss-cli": "^10.1.0" } }, @@ -76,14 +76,14 @@ "name": "@tailwindcss/integrations-parcel", "version": "0.0.0", "devDependencies": { - "parcel": "2.9.1" + "parcel": "^2.9.1" } }, "integrations/postcss-cli": { "name": "@tailwindcss/integrations-postcss-cli", "version": "0.0.0", "devDependencies": { - "postcss": "^8.4.23", + "postcss": "8.4.24", "postcss-cli": "^10.1.0" } }, @@ -11858,9 +11858,9 @@ } }, "node_modules/postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "funding": [ { "type": "opencollective", @@ -18439,20 +18439,20 @@ "@tailwindcss/integrations-content-resolution": { "version": "file:integrations/content-resolution", "requires": { - "postcss": "^8.4.23", + "postcss": "8.4.24", "postcss-cli": "^10.1.0" } }, "@tailwindcss/integrations-parcel": { "version": "file:integrations/parcel", "requires": { - "parcel": "2.9.1" + "parcel": "^2.9.1" } }, "@tailwindcss/integrations-postcss-cli": { "version": "file:integrations/postcss-cli", "requires": { - "postcss": "^8.4.23", + "postcss": "8.4.24", "postcss-cli": "^10.1.0" } }, @@ -24554,9 +24554,9 @@ "dev": true }, "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", @@ -28825,20 +28825,20 @@ "@tailwindcss/integrations-content-resolution": { "version": "file:integrations/content-resolution", "requires": { - "postcss": "^8.4.23", + "postcss": "8.4.24", "postcss-cli": "^10.1.0" } }, "@tailwindcss/integrations-parcel": { "version": "file:integrations/parcel", "requires": { - "parcel": "2.9.1" + "parcel": "^2.9.1" } }, "@tailwindcss/integrations-postcss-cli": { "version": "file:integrations/postcss-cli", "requires": { - "postcss": "^8.4.23", + "postcss": "8.4.24", "postcss-cli": "^10.1.0" } }, @@ -34940,9 +34940,9 @@ "dev": true }, "postcss": { - "version": "8.4.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.23.tgz", - "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==", + "version": "8.4.24", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", + "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", "requires": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", diff --git a/package.json b/package.json index 271e8548b..852ca7a66 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", From f661c0371c392d729c049aac1a416883b3269d21 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Sun, 4 Jun 2023 10:25:45 +0000 Subject: [PATCH 48/85] Update browserslist to version 4.21.7 --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 10d5e7c3e..c199db669 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "name": "@tailwindcss/integrations-content-resolution", "version": "0.0.0", "devDependencies": { - "postcss": "8.4.24", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, @@ -83,7 +83,7 @@ "name": "@tailwindcss/integrations-postcss-cli", "version": "0.0.0", "devDependencies": { - "postcss": "8.4.24", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, @@ -18439,7 +18439,7 @@ "@tailwindcss/integrations-content-resolution": { "version": "file:integrations/content-resolution", "requires": { - "postcss": "8.4.24", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, @@ -18452,7 +18452,7 @@ "@tailwindcss/integrations-postcss-cli": { "version": "file:integrations/postcss-cli", "requires": { - "postcss": "8.4.24", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, @@ -26381,7 +26381,7 @@ "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.23", + "postcss": "^8.4.24", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.1", @@ -28825,7 +28825,7 @@ "@tailwindcss/integrations-content-resolution": { "version": "file:integrations/content-resolution", "requires": { - "postcss": "8.4.24", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, @@ -28838,7 +28838,7 @@ "@tailwindcss/integrations-postcss-cli": { "version": "file:integrations/postcss-cli", "requires": { - "postcss": "8.4.24", + "postcss": "^8.4.24", "postcss-cli": "^10.1.0" } }, diff --git a/package.json b/package.json index 852ca7a66..890586910 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "@alloc/quick-lru": "^5.2.0", "@tailwindcss/oxide": "file:oxide/crates/node", "arg": "^5.0.2", - "browserslist": "^4.21.5", + "browserslist": "^4.21.7", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", From fd74f04437b230e1e24921ef27add14a6f9d12f7 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 04:07:23 +0000 Subject: [PATCH 49/85] Update vite to version 4.3.9 --- integrations/vite/package.json | 2 +- package-lock.json | 151 ++++++++++++++++++--------------- 2 files changed, 85 insertions(+), 68 deletions(-) diff --git a/integrations/vite/package.json b/integrations/vite/package.json index 8a76f10fe..3c412435d 100644 --- a/integrations/vite/package.json +++ b/integrations/vite/package.json @@ -21,6 +21,6 @@ }, "devDependencies": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.4" + "vite": "^4.3.9" } } diff --git a/package-lock.json b/package-lock.json index c199db669..8b9e38f47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "@alloc/quick-lru": "^5.2.0", "@tailwindcss/oxide": "file:oxide/crates/node", "arg": "^5.0.2", - "browserslist": "^4.21.5", + "browserslist": "^4.21.7", "chokidar": "^3.5.3", "didyoumean": "^1.2.2", "dlv": "^1.1.3", @@ -116,7 +116,7 @@ "version": "0.0.0", "devDependencies": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.4" + "vite": "4.3.9" } }, "integrations/webpack-4": { @@ -5636,9 +5636,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", "funding": [ { "type": "opencollective", @@ -5647,13 +5647,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -5843,9 +5847,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001468", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", - "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==", + "version": "1.0.30001495", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", + "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", "funding": [ { "type": "opencollective", @@ -5854,6 +5858,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, @@ -7049,9 +7057,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.288", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.288.tgz", - "integrity": "sha512-8s9aJf3YiokIrR+HOQzNOGmEHFXVUQzXM/JaViVvKdCkNUjS+lEa/uT7xw3nDVG/IgfxiIwUGkwJ6AR1pTpYsQ==" + "version": "1.4.421", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", + "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -11258,9 +11266,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -15036,7 +15044,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "funding": [ { "type": "opencollective", @@ -15045,15 +15055,18 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "escalade": "^3.1.1", "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -15155,9 +15168,9 @@ "dev": true }, "node_modules/vite": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz", - "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "dependencies": { "esbuild": "^0.17.5", @@ -18481,7 +18494,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.4" + "vite": "4.3.9" } }, "@tailwindcss/integrations-webpack-4": { @@ -19963,14 +19976,14 @@ } }, "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" } }, "bser": { @@ -20128,9 +20141,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001468", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", - "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==" + "version": "1.0.30001495", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", + "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==" }, "chalk": { "version": "4.1.2", @@ -21012,9 +21025,9 @@ } }, "electron-to-chromium": { - "version": "1.4.288", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.288.tgz", - "integrity": "sha512-8s9aJf3YiokIrR+HOQzNOGmEHFXVUQzXM/JaViVvKdCkNUjS+lEa/uT7xw3nDVG/IgfxiIwUGkwJ6AR1pTpYsQ==" + "version": "1.4.421", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", + "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, "elliptic": { "version": "6.5.4", @@ -24135,9 +24148,9 @@ } }, "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, "normalize-path": { "version": "3.0.0" @@ -26361,7 +26374,7 @@ "@tailwindcss/integrations-webpack-5": "file:integrations/webpack-5", "@tailwindcss/oxide": "file:oxide/crates/node", "arg": "^5.0.2", - "browserslist": "^4.21.5", + "browserslist": "^4.21.7", "chokidar": "^3.5.3", "concurrently": "^8.0.1", "didyoumean": "^1.2.2", @@ -28867,7 +28880,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "^4.3.4" + "vite": "4.3.9" } }, "@tailwindcss/integrations-webpack-4": { @@ -30349,14 +30362,14 @@ } }, "browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", + "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", "requires": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001489", + "electron-to-chromium": "^1.4.411", + "node-releases": "^2.0.12", + "update-browserslist-db": "^1.0.11" } }, "bser": { @@ -30514,9 +30527,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001468", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", - "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==" + "version": "1.0.30001495", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", + "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==" }, "chalk": { "version": "4.1.2", @@ -31398,9 +31411,9 @@ } }, "electron-to-chromium": { - "version": "1.4.288", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.288.tgz", - "integrity": "sha512-8s9aJf3YiokIrR+HOQzNOGmEHFXVUQzXM/JaViVvKdCkNUjS+lEa/uT7xw3nDVG/IgfxiIwUGkwJ6AR1pTpYsQ==" + "version": "1.4.421", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", + "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" }, "elliptic": { "version": "6.5.4", @@ -34521,9 +34534,9 @@ } }, "node-releases": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz", - "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==" + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", + "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" }, "normalize-path": { "version": "3.0.0" @@ -37191,7 +37204,9 @@ "optional": true }, "update-browserslist-db": { - "version": "1.0.10", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -37287,9 +37302,9 @@ } }, "vite": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz", - "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "requires": { "esbuild": "^0.17.5", @@ -38381,7 +38396,9 @@ "optional": true }, "update-browserslist-db": { - "version": "1.0.10", + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", + "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" @@ -38477,9 +38494,9 @@ } }, "vite": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.4.tgz", - "integrity": "sha512-f90aqGBoxSFxWph2b39ae2uHAxm5jFBBdnfueNxZAT1FTpM13ccFQExCaKbR2xFW5atowjleRniQ7onjJ22QEg==", + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", + "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", "dev": true, "requires": { "esbuild": "^0.17.5", From 571c27e1f1f995c0908a05a9cbfca385505cc65d Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Tue, 6 Jun 2023 07:55:42 +0000 Subject: [PATCH 50/85] Update @swc/core to version 1.3.62 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8b9e38f47..6c5e428ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -116,7 +116,7 @@ "version": "0.0.0", "devDependencies": { "isomorphic-fetch": "^3.0.0", - "vite": "4.3.9" + "vite": "^4.3.9" } }, "integrations/webpack-4": { @@ -18494,7 +18494,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "4.3.9" + "vite": "^4.3.9" } }, "@tailwindcss/integrations-webpack-4": { @@ -28880,7 +28880,7 @@ "version": "file:integrations/vite", "requires": { "isomorphic-fetch": "^3.0.0", - "vite": "4.3.9" + "vite": "^4.3.9" } }, "@tailwindcss/integrations-webpack-4": { diff --git a/package.json b/package.json index 890586910..0558edd3d 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ ], "devDependencies": { "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.56", + "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "concurrently": "^8.0.1", From e572dc645a74ea0eb7e2962f5fda078b4265541d Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 7 Jun 2023 15:56:32 +0200 Subject: [PATCH 51/85] Bump `lightningcss` dependency (#11388) * bump `lightningcss` * allow for non-standard selector combinators such as `::deep` * just use Prettier when comparing CSS results We were using 2 different engines where the stable one was not using Lightning CSS and the Oxide one was using Lightning CSS. To ensure that we didn't have to rewrite every single test expectation, the `toMatchFormattedCss` parsed both the actual and expected value using Lightning CSS (to make the result similar), then it used Prettier to make it... pretty. Right now we _only_ use Lightning CSS, which means that we can drop the additional lightningcss format step and just use Prettier on both the actual and expected values. Pretty also only prettifies the CSS, it doesn't rewrite it. E.g.: `@media (min-width: 768px)` will not be optimized to `@media (width >= 768px)`, that's something that Lightning CSS does for us. This will require some changes in our test output, but it will be consistent afterwards because there won't be hidden transformation steps anymore. Because up until now it could be that the actual result was `color: black` but the tests showed `color: #000` (because it is shorter). This change will reflect reality. * update tests based on previous commit * only use `toMatchFormattedCss` instead of `toMatchCss` They both do the exact same thing right now. While `toMatchCss` is shorter, `toMatchFormattedCss` makes a bit more sense since we are comparing the Prettier results. * update integration tests --- .../content-resolution/tests/content.test.js | 28 +- integrations/parcel/tests/integration.test.js | 10 +- .../postcss-cli/tests/integration.test.js | 13 +- .../rollup-sass/tests/integration.test.js | 4 +- integrations/rollup/tests/integration.test.js | 6 +- .../tailwindcss-cli/tests/cli.test.js | 16 +- .../tailwindcss-cli/tests/integration.test.js | 6 - integrations/vite/tests/integration.test.js | 11 +- .../webpack-4/tests/integration.test.js | 4 +- .../webpack-5/tests/integration.test.js | 4 +- jest/customMatchers.js | 56 +-- package-lock.json | 476 +++++++++--------- package.json | 2 +- src/plugin.js | 3 + tests/apply.test.js | 104 ++-- tests/arbitrary-properties.test.js | 2 +- tests/arbitrary-values.test.css | 6 +- tests/arbitrary-values.test.js | 2 +- tests/arbitrary-variants.test.js | 8 +- tests/basic-usage.test.css | 16 +- tests/basic-usage.test.js | 3 - tests/blocklist.test.js | 2 +- tests/collapse-adjacent-rules.test.js | 10 +- tests/collapse-duplicate-declarations.test.js | 5 - tests/containerPlugin.test.js | 60 +-- tests/custom-plugins.test.js | 38 +- tests/custom-separator.test.js | 2 +- tests/customConfig.test.js | 16 +- tests/detect-nesting.test.js | 2 +- tests/evaluateTailwindFunctions.test.js | 192 ++++--- tests/experimental.test.js | 16 +- tests/import-syntax.test.js | 12 +- tests/important-boolean.test.js | 12 +- tests/important-modifier-prefix.test.js | 14 +- tests/important-modifier.test.js | 18 +- tests/important-selector.test.js | 26 +- tests/kitchen-sink.test.js | 72 +-- tests/match-utilities.test.js | 26 +- tests/match-variants.test.js | 62 +-- tests/min-max-screen-variants.test.js | 70 +-- tests/modify-selectors.test.js | 6 +- tests/negative-prefix.test.js | 34 +- tests/oxide-svelte.test.css | 2 +- tests/parseObjectStyles.test.js | 64 +-- tests/plugins/divide.test.js | 10 +- tests/plugins/fontFamily.test.js | 8 +- tests/plugins/fontSize.test.js | 12 +- tests/postcss-plugins/nesting/index.test.js | 23 +- tests/prefix.test.js | 14 +- tests/raw-content.test.css | 14 +- tests/resolve-defaults-at-rules.test.js | 6 +- tests/responsive-and-variants-atrules.test.js | 2 +- tests/screenAtRule.test.js | 2 +- tests/source-maps.test.js | 32 +- tests/space-utilities.test.js | 4 +- tests/syntax-svelte.test.js | 8 +- tests/tailwind-screens.test.js | 4 +- tests/variant-grouping.test.skip.js | 10 +- tests/variants.test.css | 108 +++- tests/variants.test.js | 46 +- 60 files changed, 908 insertions(+), 936 deletions(-) diff --git a/integrations/content-resolution/tests/content.test.js b/integrations/content-resolution/tests/content.test.js index a4db09f1b..baf9a3543 100644 --- a/integrations/content-resolution/tests/content.test.js +++ b/integrations/content-resolution/tests/content.test.js @@ -60,7 +60,7 @@ it('looks in the CWD by default', async () => { let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-static-positive\] { --tw-content: real-static-positive; content: var(--tw-content); @@ -69,7 +69,7 @@ it('looks in the CWD by default', async () => { result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('looks in the CWD for non-config-relative paths', async () => { @@ -88,7 +88,7 @@ it('looks in the CWD for non-config-relative paths', async () => { let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-static-positive\] { --tw-content: real-static-positive; content: var(--tw-content); @@ -97,7 +97,7 @@ it('looks in the CWD for non-config-relative paths', async () => { result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('can look for content files relative to the config', async () => { @@ -113,12 +113,12 @@ it('can look for content files relative to the config', async () => { // Here `./real` doesn't exist next to the config in the root directory let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css``) + expect(result.css).toMatchFormattedCss(css``) // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-static-positive\] { --tw-content: real-static-positive; content: var(--tw-content); @@ -143,7 +143,7 @@ it('it handles ignored globs correctly when not relative to the config', async ( let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); @@ -157,7 +157,7 @@ it('it handles ignored globs correctly when not relative to the config', async ( // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('it handles ignored globs correctly when relative to the config', async () => { @@ -177,12 +177,12 @@ it('it handles ignored globs correctly when relative to the config', async () => let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); @@ -215,7 +215,7 @@ it('it can resolve symlinks for files when not relative to the config', async () let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); @@ -237,7 +237,7 @@ it('it can resolve symlinks for files when not relative to the config', async () // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) }) it('it can resolve symlinks for files when relative to the config', async () => { @@ -261,12 +261,12 @@ it('it can resolve symlinks for files when relative to the config', async () => let result = await build({ cwd: path.resolve(__dirname, '..') }) - expect(result.css).toMatchCss(``) + expect(result.css).toMatchFormattedCss(``) // But here it `./real` does exist next to the config in the `./src` directory! result = await build({ cwd: path.resolve(__dirname, '../src') }) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .content-\[real-dynamic-positive\] { --tw-content: real-dynamic-positive; content: var(--tw-content); diff --git a/integrations/parcel/tests/integration.test.js b/integrations/parcel/tests/integration.test.js index 15b007ac9..36ebe1bf0 100644 --- a/integrations/parcel/tests/integration.test.js +++ b/integrations/parcel/tests/integration.test.js @@ -263,7 +263,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -301,7 +301,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } @@ -352,11 +352,11 @@ describe('watcher', () => { expect(await readOutputFile(/index\.\w+\.css$/)).toIncludeCss( css` - /* prettier-ignore */ .btn { - border-radius: .25rem; - padding: .25rem .5rem; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; } + .font-bold { font-weight: 700; } diff --git a/integrations/postcss-cli/tests/integration.test.js b/integrations/postcss-cli/tests/integration.test.js index cd8d2a904..1144ab59d 100644 --- a/integrations/postcss-cli/tests/integration.test.js +++ b/integrations/postcss-cli/tests/integration.test.js @@ -137,7 +137,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -174,7 +174,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } @@ -247,12 +247,11 @@ describe('watcher', () => { expect(await readOutputFile('main.css')).toIncludeCss( css` - /* prettier-ignore */ .btn { - border-radius: 0.25rem; - z-index: 0; - padding: 0.25rem 0.5rem; - } + z-index: 0; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; + } .font-bold { font-weight: 700; } diff --git a/integrations/rollup-sass/tests/integration.test.js b/integrations/rollup-sass/tests/integration.test.js index 90a3831ff..f4702b951 100644 --- a/integrations/rollup-sass/tests/integration.test.js +++ b/integrations/rollup-sass/tests/integration.test.js @@ -136,7 +136,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -173,7 +173,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } diff --git a/integrations/rollup/tests/integration.test.js b/integrations/rollup/tests/integration.test.js index 970d985f8..5ebd91ba8 100644 --- a/integrations/rollup/tests/integration.test.js +++ b/integrations/rollup/tests/integration.test.js @@ -224,7 +224,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -261,7 +261,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } @@ -334,8 +334,8 @@ describe('watcher', () => { expect(await readOutputFile('index.css')).toIncludeCss( css` .btn { - border-radius: 0.25rem; z-index: 0; + border-radius: 0.25rem; padding: 0.25rem 0.5rem; } .font-bold { diff --git a/integrations/tailwindcss-cli/tests/cli.test.js b/integrations/tailwindcss-cli/tests/cli.test.js index 0ae5e056f..7647c6639 100644 --- a/integrations/tailwindcss-cli/tests/cli.test.js +++ b/integrations/tailwindcss-cli/tests/cli.test.js @@ -150,7 +150,7 @@ describe('Build command', () => { theme: { extend: { fontWeight: { - bold: 'BOLD', + bold: 'bold', }, }, }, @@ -171,7 +171,7 @@ describe('Build command', () => { expect(await readOutputFile('main.css')).toIncludeCss( css` .font-bold { - font-weight: BOLD; + font-weight: bold; } ` ) @@ -231,11 +231,8 @@ describe('Build command', () => { } .btn-after { + padding: 0.25rem 0.5rem; display: flex; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; } ` ) @@ -281,11 +278,8 @@ describe('Build command', () => { } .btn-after { + padding: 0.25rem 0.5rem; display: flex; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; } ` ) @@ -437,7 +431,7 @@ describe('Build command', () => { css` @media (min-width: 768px) { .md\:something-cool { - color: blue; + color: #00f; } } ` diff --git a/integrations/tailwindcss-cli/tests/integration.test.js b/integrations/tailwindcss-cli/tests/integration.test.js index c72728dd6..ce02e7fdd 100644 --- a/integrations/tailwindcss-cli/tests/integration.test.js +++ b/integrations/tailwindcss-cli/tests/integration.test.js @@ -884,7 +884,6 @@ describe('watcher', () => { expect(await readOutputFile('main.css')).not.toIncludeCss( css` .underline { - -webkit-text-decoration-line: underline; text-decoration-line: underline; } ` @@ -898,7 +897,6 @@ describe('watcher', () => { expect(await readOutputFile('main.css')).toIncludeCss( css` .underline { - -webkit-text-decoration-line: underline; text-decoration-line: underline; } ` @@ -938,7 +936,6 @@ describe('watcher', () => { expect(await readOutputFile('main.css')).not.toIncludeCss( css` .underline { - -webkit-text-decoration-line: underline; text-decoration-line: underline; } ` @@ -952,7 +949,6 @@ describe('watcher', () => { expect(await readOutputFile('main.css')).toIncludeCss( css` .underline { - -webkit-text-decoration-line: underline; text-decoration-line: underline; } ` @@ -1037,7 +1033,6 @@ describe('watcher', () => { } .underline { - -webkit-text-decoration-line: underline; text-decoration-line: underline; } ` @@ -1082,7 +1077,6 @@ describe('watcher', () => { } .underline { - -webkit-text-decoration-line: underline; text-decoration-line: underline; } ` diff --git a/integrations/vite/tests/integration.test.js b/integrations/vite/tests/integration.test.js index cb106ac59..90ec78ccc 100644 --- a/integrations/vite/tests/integration.test.js +++ b/integrations/vite/tests/integration.test.js @@ -255,7 +255,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -292,7 +292,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } @@ -373,12 +373,9 @@ describe('watcher', () => { expect(await fetchCSS()).toIncludeCss( css` .btn { - border-radius: 0.25rem; z-index: 0; - padding-left: 0.5rem; - padding-right: 0.5rem; - padding-top: 0.25rem; - padding-bottom: 0.25rem; + border-radius: 0.25rem; + padding: 0.25rem 0.5rem; } .font-bold { font-weight: 700; diff --git a/integrations/webpack-4/tests/integration.test.js b/integrations/webpack-4/tests/integration.test.js index ae7011edd..e962a5402 100644 --- a/integrations/webpack-4/tests/integration.test.js +++ b/integrations/webpack-4/tests/integration.test.js @@ -225,7 +225,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -263,7 +263,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } diff --git a/integrations/webpack-5/tests/integration.test.js b/integrations/webpack-5/tests/integration.test.js index c1f0a0629..487012c4b 100644 --- a/integrations/webpack-5/tests/integration.test.js +++ b/integrations/webpack-5/tests/integration.test.js @@ -225,7 +225,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-medium { font-weight: 500; } @@ -263,7 +263,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (min-width: 800px) { + @media (width >= 800px) { .md\:font-medium { font-weight: 500; } diff --git a/jest/customMatchers.js b/jest/customMatchers.js index 9b1c6b6d0..ad0b61ef1 100644 --- a/jest/customMatchers.js +++ b/jest/customMatchers.js @@ -1,6 +1,5 @@ const prettier = require('prettier') const { diff } = require('jest-diff') -const lightningcss = require('lightningcss') const log = require('../src/util/log').default let warn @@ -22,46 +21,7 @@ function formatPrettier(input) { } function format(input) { - try { - return lightningcss - .transform({ - filename: 'input.css', - code: Buffer.from(input), - minify: false, - targets: { chrome: 106 << 16 }, - drafts: { - nesting: true, - customMedia: true, - }, - }) - .code.toString('utf8') - } catch (err) { - try { - // Lightning CSS is pretty strict, so it will fail for `@media screen(md) {}` for example, - // in that case we can fallback to prettier since it doesn't really care. However if an - // actual syntax error is made, then we still want to show the proper error. - return formatPrettier(input.replace(/\n/g, '')) - } catch { - let lines = err.source.split('\n') - let e = new Error( - [ - 'Error formatting using Lightning CSS:', - '', - ...[ - '```css', - ...lines.slice(Math.max(err.loc.line - 3, 0), err.loc.line), - ' '.repeat(err.loc.column - 1) + '^-- ' + err.toString(), - ...lines.slice(err.loc.line, err.loc.line + 2), - '```', - ], - ].join('\n') - ) - if (Error.captureStackTrace) { - Error.captureStackTrace(e, toMatchFormattedCss) - } - throw e - } - } + return formatPrettier(input).replace(/\n{2,}/g, '\n') } function toMatchFormattedCss(received = '', argument = '') { @@ -86,10 +46,7 @@ function toMatchFormattedCss(received = '', argument = '') { ) } : () => { - let actual = formatPrettier(formattedReceived).replace(/\n\n/g, '\n') - let expected = formatPrettier(formattedArgument).replace(/\n\n/g, '\n') - - let diffString = diff(expected, actual, { + let diffString = diff(formattedArgument, formattedArgument, { expand: this.expand, }) @@ -98,8 +55,8 @@ function toMatchFormattedCss(received = '', argument = '') { '\n\n' + (diffString && diffString.includes('- Expect') ? `Difference:\n\n${diffString}` - : `Expected: ${this.utils.printExpected(expected)}\n` + - `Received: ${this.utils.printReceived(actual)}`) + : `Expected: ${this.utils.printExpected(formattedArgument)}\n` + + `Received: ${this.utils.printReceived(formattedReceived)}`) ) } @@ -107,13 +64,10 @@ function toMatchFormattedCss(received = '', argument = '') { } expect.extend({ - // Compare two CSS strings with all whitespace removed - // This is probably naive but it's fast and works well enough. - toMatchCss: toMatchFormattedCss, toMatchFormattedCss: toMatchFormattedCss, toIncludeCss(received, argument) { let options = { - comment: 'stripped(received).includes(stripped(argument))', + comment: 'formatCSS(received).includes(formatCSS(argument))', isNot: this.isNot, promise: this.promise, } diff --git a/package-lock.json b/package-lock.json index 6c5e428ec..057500410 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,7 +24,7 @@ "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", - "lightningcss": "^1.18.0", + "lightningcss": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -46,7 +46,7 @@ }, "devDependencies": { "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.56", + "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "concurrently": "^8.0.1", @@ -3967,9 +3967,9 @@ } }, "node_modules/@swc/core": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.57.tgz", - "integrity": "sha512-gAT80hOVeK5qoi+BRlgXWgJYI9cbQn2oi05A09Tvb6vjFgBsr9SlQGNZB9uMlcXRXspkZFf9l3yyWRtT4we3Yw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz", + "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==", "dev": true, "hasInstallScript": true, "engines": { @@ -3980,16 +3980,16 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.57", - "@swc/core-darwin-x64": "1.3.57", - "@swc/core-linux-arm-gnueabihf": "1.3.57", - "@swc/core-linux-arm64-gnu": "1.3.57", - "@swc/core-linux-arm64-musl": "1.3.57", - "@swc/core-linux-x64-gnu": "1.3.57", - "@swc/core-linux-x64-musl": "1.3.57", - "@swc/core-win32-arm64-msvc": "1.3.57", - "@swc/core-win32-ia32-msvc": "1.3.57", - "@swc/core-win32-x64-msvc": "1.3.57" + "@swc/core-darwin-arm64": "1.3.62", + "@swc/core-darwin-x64": "1.3.62", + "@swc/core-linux-arm-gnueabihf": "1.3.62", + "@swc/core-linux-arm64-gnu": "1.3.62", + "@swc/core-linux-arm64-musl": "1.3.62", + "@swc/core-linux-x64-gnu": "1.3.62", + "@swc/core-linux-x64-musl": "1.3.62", + "@swc/core-win32-arm64-msvc": "1.3.62", + "@swc/core-win32-ia32-msvc": "1.3.62", + "@swc/core-win32-x64-msvc": "1.3.62" }, "peerDependencies": { "@swc/helpers": "^0.5.0" @@ -4001,9 +4001,9 @@ } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.57.tgz", - "integrity": "sha512-lhAK9kF/ppZdNTdaxJl2gE0bXubzQXTgxB2Xojme/1sbOipaLTskBbJ3FLySChpmVOzD0QSCTiW8w/dmQxqNIQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz", + "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==", "cpu": [ "arm64" ], @@ -4017,9 +4017,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.57.tgz", - "integrity": "sha512-jsTDH8Et/xdOM/ZCNvtrT6J8FT255OrMhEDvHZQZTgoky4oW/3FHUfji4J2FE97gitJqNJI8MuNuiGq81pIJRw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz", + "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==", "cpu": [ "x64" ], @@ -4033,9 +4033,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.57.tgz", - "integrity": "sha512-MZv3fwcCmppbwfCWaE8cZvzbXOjX7n5SEC1hF2lgItTqp4S04dFk1iX50jKr6xS6xSLlRBPqDxwZH0sBpHaEuA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz", + "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==", "cpu": [ "arm" ], @@ -4049,9 +4049,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.57.tgz", - "integrity": "sha512-wUeqa/qbkOEGl6TaDQZZL7txrQXs1vL7ERjPYhi9El+ywacFY/rTW2pK5DqaNk2eulVnLhbbNjsE1OMGSEWGkQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz", + "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==", "cpu": [ "arm64" ], @@ -4065,9 +4065,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.57.tgz", - "integrity": "sha512-pZfp1B9XfH7ZhDKFjr4qbyM093zU2Ri0IZq2M2A4W9q92+Ivy8oEIqw+gSRO3jwMDqRMEtFD49YuFhkJQakxdA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz", + "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==", "cpu": [ "arm64" ], @@ -4081,9 +4081,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.57.tgz", - "integrity": "sha512-dvtQnv07NikV+CJ+9PYJ3fqphSigzfvSUH6wRCmb5OzLDDLFnPLMrEO0pGeURvdIWCOhngcHF252C1Hl5uFSzA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz", + "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==", "cpu": [ "x64" ], @@ -4097,9 +4097,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.57.tgz", - "integrity": "sha512-1TKCSngyQxpzwBYDzF5MrEfYRDhlzt/GN1ZqlSnsJIPGkABOWZxYDvWJuMrkASdIztn3jSTPU2ih7rR7YQ8IIw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz", + "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==", "cpu": [ "x64" ], @@ -4113,9 +4113,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.57.tgz", - "integrity": "sha512-HvBYFyf4uBua/jyTrcFLKcq8SIbKVYfz2qWsbgSAZvuQPZvDC1XhN5EDH2tPZmT97F0CJx3fltH5nli6XY1/EQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz", + "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==", "cpu": [ "arm64" ], @@ -4129,9 +4129,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.57.tgz", - "integrity": "sha512-PS8AtK9e6Rp97S0ek9W5VCZNCbDaHBUasiJUmaYqRVCq/Mn6S7eQlhd0iUDnjsagigQtoCRgMUzkVknd1tarsQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz", + "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==", "cpu": [ "ia32" ], @@ -4145,9 +4145,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.57.tgz", - "integrity": "sha512-A6aX/Rpp0v3g7Spf3LSwR+ivviH8x+1xla612KLZmlc0yymWt9BMd3CmBkzyRBr2e41zGCrkf6tra6wgtCbAwA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz", + "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==", "cpu": [ "x64" ], @@ -10378,9 +10378,9 @@ } }, "node_modules/lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.0.tgz", + "integrity": "sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==", "dependencies": { "detect-libc": "^1.0.3" }, @@ -10392,20 +10392,20 @@ "url": "https://opencollective.com/parcel" }, "optionalDependencies": { - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" + "lightningcss-darwin-arm64": "1.21.0", + "lightningcss-darwin-x64": "1.21.0", + "lightningcss-linux-arm-gnueabihf": "1.21.0", + "lightningcss-linux-arm64-gnu": "1.21.0", + "lightningcss-linux-arm64-musl": "1.21.0", + "lightningcss-linux-x64-gnu": "1.21.0", + "lightningcss-linux-x64-musl": "1.21.0", + "lightningcss-win32-x64-msvc": "1.21.0" } }, "node_modules/lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.0.tgz", + "integrity": "sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==", "cpu": [ "arm64" ], @@ -10422,9 +10422,9 @@ } }, "node_modules/lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.0.tgz", + "integrity": "sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==", "cpu": [ "x64" ], @@ -10441,9 +10441,9 @@ } }, "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.0.tgz", + "integrity": "sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==", "cpu": [ "arm" ], @@ -10460,9 +10460,9 @@ } }, "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.0.tgz", + "integrity": "sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==", "cpu": [ "arm64" ], @@ -10479,9 +10479,9 @@ } }, "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.0.tgz", + "integrity": "sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==", "cpu": [ "arm64" ], @@ -10498,9 +10498,9 @@ } }, "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.0.tgz", + "integrity": "sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==", "cpu": [ "x64" ], @@ -10517,9 +10517,9 @@ } }, "node_modules/lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.0.tgz", + "integrity": "sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==", "cpu": [ "x64" ], @@ -10536,9 +10536,9 @@ } }, "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.0.tgz", + "integrity": "sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==", "cpu": [ "x64" ], @@ -18323,90 +18323,90 @@ } }, "@swc/core": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.57.tgz", - "integrity": "sha512-gAT80hOVeK5qoi+BRlgXWgJYI9cbQn2oi05A09Tvb6vjFgBsr9SlQGNZB9uMlcXRXspkZFf9l3yyWRtT4we3Yw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz", + "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==", "dev": true, "requires": { - "@swc/core-darwin-arm64": "1.3.57", - "@swc/core-darwin-x64": "1.3.57", - "@swc/core-linux-arm-gnueabihf": "1.3.57", - "@swc/core-linux-arm64-gnu": "1.3.57", - "@swc/core-linux-arm64-musl": "1.3.57", - "@swc/core-linux-x64-gnu": "1.3.57", - "@swc/core-linux-x64-musl": "1.3.57", - "@swc/core-win32-arm64-msvc": "1.3.57", - "@swc/core-win32-ia32-msvc": "1.3.57", - "@swc/core-win32-x64-msvc": "1.3.57" + "@swc/core-darwin-arm64": "1.3.62", + "@swc/core-darwin-x64": "1.3.62", + "@swc/core-linux-arm-gnueabihf": "1.3.62", + "@swc/core-linux-arm64-gnu": "1.3.62", + "@swc/core-linux-arm64-musl": "1.3.62", + "@swc/core-linux-x64-gnu": "1.3.62", + "@swc/core-linux-x64-musl": "1.3.62", + "@swc/core-win32-arm64-msvc": "1.3.62", + "@swc/core-win32-ia32-msvc": "1.3.62", + "@swc/core-win32-x64-msvc": "1.3.62" } }, "@swc/core-darwin-arm64": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.57.tgz", - "integrity": "sha512-lhAK9kF/ppZdNTdaxJl2gE0bXubzQXTgxB2Xojme/1sbOipaLTskBbJ3FLySChpmVOzD0QSCTiW8w/dmQxqNIQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz", + "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.57.tgz", - "integrity": "sha512-jsTDH8Et/xdOM/ZCNvtrT6J8FT255OrMhEDvHZQZTgoky4oW/3FHUfji4J2FE97gitJqNJI8MuNuiGq81pIJRw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz", + "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.57.tgz", - "integrity": "sha512-MZv3fwcCmppbwfCWaE8cZvzbXOjX7n5SEC1hF2lgItTqp4S04dFk1iX50jKr6xS6xSLlRBPqDxwZH0sBpHaEuA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz", + "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.57.tgz", - "integrity": "sha512-wUeqa/qbkOEGl6TaDQZZL7txrQXs1vL7ERjPYhi9El+ywacFY/rTW2pK5DqaNk2eulVnLhbbNjsE1OMGSEWGkQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz", + "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.57.tgz", - "integrity": "sha512-pZfp1B9XfH7ZhDKFjr4qbyM093zU2Ri0IZq2M2A4W9q92+Ivy8oEIqw+gSRO3jwMDqRMEtFD49YuFhkJQakxdA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz", + "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.57.tgz", - "integrity": "sha512-dvtQnv07NikV+CJ+9PYJ3fqphSigzfvSUH6wRCmb5OzLDDLFnPLMrEO0pGeURvdIWCOhngcHF252C1Hl5uFSzA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz", + "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.57.tgz", - "integrity": "sha512-1TKCSngyQxpzwBYDzF5MrEfYRDhlzt/GN1ZqlSnsJIPGkABOWZxYDvWJuMrkASdIztn3jSTPU2ih7rR7YQ8IIw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz", + "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.57.tgz", - "integrity": "sha512-HvBYFyf4uBua/jyTrcFLKcq8SIbKVYfz2qWsbgSAZvuQPZvDC1XhN5EDH2tPZmT97F0CJx3fltH5nli6XY1/EQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz", + "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.57.tgz", - "integrity": "sha512-PS8AtK9e6Rp97S0ek9W5VCZNCbDaHBUasiJUmaYqRVCq/Mn6S7eQlhd0iUDnjsagigQtoCRgMUzkVknd1tarsQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz", + "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.57.tgz", - "integrity": "sha512-A6aX/Rpp0v3g7Spf3LSwR+ivviH8x+1xla612KLZmlc0yymWt9BMd3CmBkzyRBr2e41zGCrkf6tra6wgtCbAwA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz", + "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==", "dev": true, "optional": true }, @@ -23528,67 +23528,67 @@ } }, "lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.0.tgz", + "integrity": "sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==", "requires": { "detect-libc": "^1.0.3", - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" + "lightningcss-darwin-arm64": "1.21.0", + "lightningcss-darwin-x64": "1.21.0", + "lightningcss-linux-arm-gnueabihf": "1.21.0", + "lightningcss-linux-arm64-gnu": "1.21.0", + "lightningcss-linux-arm64-musl": "1.21.0", + "lightningcss-linux-x64-gnu": "1.21.0", + "lightningcss-linux-x64-musl": "1.21.0", + "lightningcss-win32-x64-msvc": "1.21.0" } }, "lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.0.tgz", + "integrity": "sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==", "optional": true }, "lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.0.tgz", + "integrity": "sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==", "optional": true }, "lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.0.tgz", + "integrity": "sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==", "optional": true }, "lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.0.tgz", + "integrity": "sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==", "optional": true }, "lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.0.tgz", + "integrity": "sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==", "optional": true }, "lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.0.tgz", + "integrity": "sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==", "optional": true }, "lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.0.tgz", + "integrity": "sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==", "optional": true }, "lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.0.tgz", + "integrity": "sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==", "optional": true }, "lilconfig": { @@ -26360,7 +26360,7 @@ "requires": { "@alloc/quick-lru": "^5.2.0", "@swc/cli": "^0.1.62", - "@swc/core": "^1.3.56", + "@swc/core": "^1.3.62", "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "@tailwindcss/integrations-content-resolution": "file:integrations/content-resolution", @@ -26388,7 +26388,7 @@ "jest": "^29.5.0", "jest-diff": "^29.5.0", "jiti": "^1.18.2", - "lightningcss": "^1.18.0", + "lightningcss": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", @@ -28709,90 +28709,90 @@ } }, "@swc/core": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.57.tgz", - "integrity": "sha512-gAT80hOVeK5qoi+BRlgXWgJYI9cbQn2oi05A09Tvb6vjFgBsr9SlQGNZB9uMlcXRXspkZFf9l3yyWRtT4we3Yw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.62.tgz", + "integrity": "sha512-J58hWY+/G8vOr4J6ZH9hLg0lMSijZtqIIf4HofZezGog/pVX6sJyBJ40dZ1ploFkDIlWTWvJyqtpesBKS73gkQ==", "dev": true, "requires": { - "@swc/core-darwin-arm64": "1.3.57", - "@swc/core-darwin-x64": "1.3.57", - "@swc/core-linux-arm-gnueabihf": "1.3.57", - "@swc/core-linux-arm64-gnu": "1.3.57", - "@swc/core-linux-arm64-musl": "1.3.57", - "@swc/core-linux-x64-gnu": "1.3.57", - "@swc/core-linux-x64-musl": "1.3.57", - "@swc/core-win32-arm64-msvc": "1.3.57", - "@swc/core-win32-ia32-msvc": "1.3.57", - "@swc/core-win32-x64-msvc": "1.3.57" + "@swc/core-darwin-arm64": "1.3.62", + "@swc/core-darwin-x64": "1.3.62", + "@swc/core-linux-arm-gnueabihf": "1.3.62", + "@swc/core-linux-arm64-gnu": "1.3.62", + "@swc/core-linux-arm64-musl": "1.3.62", + "@swc/core-linux-x64-gnu": "1.3.62", + "@swc/core-linux-x64-musl": "1.3.62", + "@swc/core-win32-arm64-msvc": "1.3.62", + "@swc/core-win32-ia32-msvc": "1.3.62", + "@swc/core-win32-x64-msvc": "1.3.62" } }, "@swc/core-darwin-arm64": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.57.tgz", - "integrity": "sha512-lhAK9kF/ppZdNTdaxJl2gE0bXubzQXTgxB2Xojme/1sbOipaLTskBbJ3FLySChpmVOzD0QSCTiW8w/dmQxqNIQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.62.tgz", + "integrity": "sha512-MmGilibITz68LEje6vJlKzc2gUUSgzvB3wGLSjEORikTNeM7P8jXVxE4A8fgZqDeudJUm9HVWrxCV+pHDSwXhA==", "dev": true, "optional": true }, "@swc/core-darwin-x64": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.57.tgz", - "integrity": "sha512-jsTDH8Et/xdOM/ZCNvtrT6J8FT255OrMhEDvHZQZTgoky4oW/3FHUfji4J2FE97gitJqNJI8MuNuiGq81pIJRw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.62.tgz", + "integrity": "sha512-Xl93MMB3sCWVlYWuQIB+v6EQgzoiuQYK5tNt9lsHoIEVu2zLdkQjae+5FUHZb1VYqCXIiWcULFfVz0R4Sjb7JQ==", "dev": true, "optional": true }, "@swc/core-linux-arm-gnueabihf": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.57.tgz", - "integrity": "sha512-MZv3fwcCmppbwfCWaE8cZvzbXOjX7n5SEC1hF2lgItTqp4S04dFk1iX50jKr6xS6xSLlRBPqDxwZH0sBpHaEuA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.62.tgz", + "integrity": "sha512-nJsp6O7kCtAjTTMcIjVB0g5y1JNiYAa5q630eiwrnaHUusEFoANDdORI3Z9vXeikMkng+6yIv9/V8Rb093xLjQ==", "dev": true, "optional": true }, "@swc/core-linux-arm64-gnu": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.57.tgz", - "integrity": "sha512-wUeqa/qbkOEGl6TaDQZZL7txrQXs1vL7ERjPYhi9El+ywacFY/rTW2pK5DqaNk2eulVnLhbbNjsE1OMGSEWGkQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.62.tgz", + "integrity": "sha512-XGsV93vpUAopDt5y6vPwbK1Nc/MlL55L77bAZUPIiosWD1cWWPHNtNSpriE6+I+JiMHe0pqtfS/SSTk6ZkFQVw==", "dev": true, "optional": true }, "@swc/core-linux-arm64-musl": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.57.tgz", - "integrity": "sha512-pZfp1B9XfH7ZhDKFjr4qbyM093zU2Ri0IZq2M2A4W9q92+Ivy8oEIqw+gSRO3jwMDqRMEtFD49YuFhkJQakxdA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.62.tgz", + "integrity": "sha512-ESUmJjSlTTkoBy9dMG49opcNn8BmviqStMhwyeD1G8XRnmRVCZZgoBOKdvCXmJhw8bQXDhZumeaTUB+OFUKVXg==", "dev": true, "optional": true }, "@swc/core-linux-x64-gnu": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.57.tgz", - "integrity": "sha512-dvtQnv07NikV+CJ+9PYJ3fqphSigzfvSUH6wRCmb5OzLDDLFnPLMrEO0pGeURvdIWCOhngcHF252C1Hl5uFSzA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.62.tgz", + "integrity": "sha512-wnHJkt3ZBrax3SFnUHDcncG6mrSg9ZZjMhQV9Mc3JL1x1s1Gy9rGZCoBNnV/BUZWTemxIBcQbANRSDut/WO+9A==", "dev": true, "optional": true }, "@swc/core-linux-x64-musl": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.57.tgz", - "integrity": "sha512-1TKCSngyQxpzwBYDzF5MrEfYRDhlzt/GN1ZqlSnsJIPGkABOWZxYDvWJuMrkASdIztn3jSTPU2ih7rR7YQ8IIw==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.62.tgz", + "integrity": "sha512-9oRbuTC/VshB66Rgwi3pTq3sPxSTIb8k9L1vJjES+dDMKa29DAjPtWCXG/pyZ00ufpFZgkGEuAHH5uqUcr1JQg==", "dev": true, "optional": true }, "@swc/core-win32-arm64-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.57.tgz", - "integrity": "sha512-HvBYFyf4uBua/jyTrcFLKcq8SIbKVYfz2qWsbgSAZvuQPZvDC1XhN5EDH2tPZmT97F0CJx3fltH5nli6XY1/EQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.62.tgz", + "integrity": "sha512-zv14vlF2VRrxS061XkfzGjCYnOrEo5glKJjLK5PwUKysIoVrx/L8nAbFxjkX5cObdlyoqo+ekelyBPAO+4bS0w==", "dev": true, "optional": true }, "@swc/core-win32-ia32-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.57.tgz", - "integrity": "sha512-PS8AtK9e6Rp97S0ek9W5VCZNCbDaHBUasiJUmaYqRVCq/Mn6S7eQlhd0iUDnjsagigQtoCRgMUzkVknd1tarsQ==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.62.tgz", + "integrity": "sha512-8MC/PZQSsOP2iA/81tAfNRqMWyEqTS/8zKUI67vPuLvpx6NAjRn3E9qBv7iFqH79iqZNzqSMo3awnLrKZyFbcw==", "dev": true, "optional": true }, "@swc/core-win32-x64-msvc": { - "version": "1.3.57", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.57.tgz", - "integrity": "sha512-A6aX/Rpp0v3g7Spf3LSwR+ivviH8x+1xla612KLZmlc0yymWt9BMd3CmBkzyRBr2e41zGCrkf6tra6wgtCbAwA==", + "version": "1.3.62", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.62.tgz", + "integrity": "sha512-GJSmUJ95HKHZXAxiuPUmrcm/S3ivQvEzXhOZaIqYBIwUsm02vFZkClsV7eIKzWjso1t0+I/8MjrnUNaSWqh1rQ==", "dev": true, "optional": true }, @@ -33914,67 +33914,67 @@ } }, "lightningcss": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.18.0.tgz", - "integrity": "sha512-uk10tNxi5fhZqU93vtYiQgx/8a9f0Kvtj5AXIm+VlOXY+t/DWDmCZWJEkZJmmALgvbS6aAW8or+Kq85eJ6TDTw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.21.0.tgz", + "integrity": "sha512-HDznZexdDMvC98c79vRE+oW5vFncTlLjJopzK4azReOilq6n4XIscCMhvgiXkstYMM/dCe6FJw0oed06ck8AtA==", "requires": { "detect-libc": "^1.0.3", - "lightningcss-darwin-arm64": "1.18.0", - "lightningcss-darwin-x64": "1.18.0", - "lightningcss-linux-arm-gnueabihf": "1.18.0", - "lightningcss-linux-arm64-gnu": "1.18.0", - "lightningcss-linux-arm64-musl": "1.18.0", - "lightningcss-linux-x64-gnu": "1.18.0", - "lightningcss-linux-x64-musl": "1.18.0", - "lightningcss-win32-x64-msvc": "1.18.0" + "lightningcss-darwin-arm64": "1.21.0", + "lightningcss-darwin-x64": "1.21.0", + "lightningcss-linux-arm-gnueabihf": "1.21.0", + "lightningcss-linux-arm64-gnu": "1.21.0", + "lightningcss-linux-arm64-musl": "1.21.0", + "lightningcss-linux-x64-gnu": "1.21.0", + "lightningcss-linux-x64-musl": "1.21.0", + "lightningcss-win32-x64-msvc": "1.21.0" } }, "lightningcss-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-OqjydwtiNPgdH1ByIjA1YzqvDG/OMR6L3LPN6wRl1729LB0y4Mik7L06kmZaTb+pvUHr+NmDd2KCwnlrQ4zO3w==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.21.0.tgz", + "integrity": "sha512-WcJmVmbNUnCbUqqXV46ZsriFtWJujcPkn+w2cu4R+EgpXuibyTP/gzahmX0gc4RYQxTz2zXIeGx4cF2gr8fLwA==", "optional": true }, "lightningcss-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.18.0.tgz", - "integrity": "sha512-mNiuPHj89/JHZmJMp+5H8EZSt6EL5DZRWJ31O6k3DrLLnRIQjXuXdDdN8kP7LoIkeWI5xvyD60CsReJm+YWYAw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.21.0.tgz", + "integrity": "sha512-xHwMHfcTIHX6fY4YQimI1V/KcbozoNVeKMncZzrp/3NAj0sp3ktxobCj1e0sGqVJMUMaHu/SWvt0mS8jAIhkYw==", "optional": true }, "lightningcss-linux-arm-gnueabihf": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.18.0.tgz", - "integrity": "sha512-S+25JjI6601HiAVoTDXW6SqH+E94a+FHA7WQqseyNHunOgVWKcAkNEc2LJvVxgwTq6z41sDIb9/M3Z9wa9lk4A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.21.0.tgz", + "integrity": "sha512-rk1cr+C2IA1QHvh0QJAPXsQ2vrwCksms7fgfaw43RIERBWa6EEM5p0/1CWhdZ5zrl9veUdY6NRaNGRJjJL0iLw==", "optional": true }, "lightningcss-linux-arm64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.18.0.tgz", - "integrity": "sha512-JSqh4+21dCgBecIQUet35dtE4PhhSEMyqe3y0ZNQrAJQ5kyUPSQHiw81WXnPJcOSTTpG0TyMLiC8K//+BsFGQA==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.21.0.tgz", + "integrity": "sha512-JkOG8K2Y4m5MeP3DlaHOgGDDtHbhbJcN8JcizFN0snUIIru1qxYNWPhAQsEwysuTRY9aANP0nScZJkALpcYmgA==", "optional": true }, "lightningcss-linux-arm64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.18.0.tgz", - "integrity": "sha512-2FWHa8iUhShnZnqhn2wfIcK5adJat9hAAaX7etNsoXJymlliDIOFuBQEsba2KBAZSM4QqfQtvRdR7m8i0I7ybQ==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.21.0.tgz", + "integrity": "sha512-4Zx51DbR41neTFMs28CI9cZpX/mF5Urc6pChTio5nZhrz6FC1pRGiwxNJ+G15a/YPvRmPmvQd3Mz1N4WEgbj2A==", "optional": true }, "lightningcss-linux-x64-gnu": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.18.0.tgz", - "integrity": "sha512-plCPGQJtDZHcLVKVRLnQVF2XRsIC32WvuJhQ7fJ7F6BV98b/VZX0OlX05qUaOESD9dCDHjYSfxsgcvOKgCWh7A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.21.0.tgz", + "integrity": "sha512-PN33pPK/O3b4qMfWcJ2eis7NLqEkyW2NEh9X4rWfJrBtOnSbgafuYUuEtO5Ylu+dL3oUKc5usB07FGeil3RzeA==", "optional": true }, "lightningcss-linux-x64-musl": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.18.0.tgz", - "integrity": "sha512-na+BGtVU6fpZvOHKhnlA0XHeibkT3/46nj6vLluG3kzdJYoBKU6dIl7DSOk++8jv4ybZyFJ0aOFMMSc8g2h58A==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.21.0.tgz", + "integrity": "sha512-S51OT7TRfS5x8aN/8frv/JSXCGm+11VuhM4WCiTqDPjhHUDWd8nwiN/7s5juiwrlrpOxb5UKq21EKDrISoGQpw==", "optional": true }, "lightningcss-win32-x64-msvc": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.18.0.tgz", - "integrity": "sha512-5qeAH4RMNy2yMNEl7e5TI6upt/7xD2ZpHWH4RkT8iJ7/6POS5mjHbXWUO9Q1hhDhqkdzGa76uAdMzEouIeCyNw==", + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.21.0.tgz", + "integrity": "sha512-yW6/ZDJAHrSWtRltH1tr2I+2sn374gK2yclc44HMfpxfjIYgXMUkzqstalloMUQpZFR6M0ltXo5/tuLWoBydGQ==", "optional": true }, "lilconfig": { diff --git a/package.json b/package.json index 0558edd3d..df3995be3 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,7 @@ "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.18.2", - "lightningcss": "^1.18.0", + "lightningcss": "^1.21.0", "lilconfig": "^2.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", diff --git a/src/plugin.js b/src/plugin.js index 3c62c1913..849d95e2a 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -63,6 +63,9 @@ module.exports = function tailwindcss(configOrPath) { nesting: true, customMedia: true, }, + nonStandard: { + deepSelectorCombinator: true, + }, }) let code = transformed.code.toString() diff --git a/tests/apply.test.js b/tests/apply.test.js index 6f3abd2a9..e7627fb13 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -181,12 +181,12 @@ test('@apply', () => { .variants:focus { font-weight: 500; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .variants { font-weight: 300; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .variants:focus { font-weight: 900; } @@ -197,12 +197,12 @@ test('@apply', () => { .only-variants:focus { font-weight: 500; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .only-variants { font-weight: 300; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .only-variants:focus { font-weight: 900; } @@ -210,7 +210,7 @@ test('@apply', () => { .group:hover .apply-group-variant { text-align: center; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .group:hover .apply-group-variant { text-align: left; } @@ -221,7 +221,7 @@ test('@apply', () => { :is(.dark .apply-dark-variant:hover) { text-align: right; } - @media (min-width: 1024px) { + @media (width >= 1024px) { :is(.dark .apply-dark-variant) { text-align: left; } @@ -230,12 +230,12 @@ test('@apply', () => { .apply-custom-utility:hover { custom: stuff; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .apply-custom-utility { custom: stuff; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .apply-custom-utility:focus { custom: stuff; } @@ -255,7 +255,7 @@ test('@apply', () => { .selectors-variants:active { text-align: right; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .multiple-variants:focus, .selectors-variants:focus { text-align: left; @@ -265,7 +265,7 @@ test('@apply', () => { .group:hover .selectors-group { text-align: center; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .group:hover .multiple-group, .group:hover .selectors-group { text-align: left; @@ -321,15 +321,12 @@ test('@apply', () => { .recursive-apply-a { font-weight: 900; } - @media (min-width: 640px) { + @media (width >= 640px) { .recursive-apply-a { font-weight: 100; } } - .recursive-apply-b { - font-weight: 900; - } - @media (min-width: 640px) { + @media (width >= 640px) { .recursive-apply-b { font-weight: 100; } @@ -337,23 +334,17 @@ test('@apply', () => { .recursive-apply-b { font-weight: 600; } - @media (min-width: 768px) { + @media (width >= 768px) { .recursive-apply-b { font-weight: 200; } } - .recursive-apply-c { - font-weight: 900; - } - @media (min-width: 640px) { + @media (width >= 640px) { .recursive-apply-c { font-weight: 100; } } - .recursive-apply-c { - font-weight: 600; - } - @media (min-width: 768px) { + @media (width >= 768px) { .recursive-apply-c { font-weight: 200; } @@ -361,7 +352,7 @@ test('@apply', () => { .recursive-apply-c { font-weight: 700; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .recursive-apply-c { font-weight: 300; } @@ -378,13 +369,13 @@ test('@apply', () => { padding-left: 0.5rem; padding-right: 0.5rem; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .add-sibling-properties { padding-left: 2.5rem; padding-right: 2.5rem; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .add-sibling-properties:focus { padding-left: 0.25rem; padding-right: 0.25rem; @@ -399,13 +390,13 @@ test('@apply', () => { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 640px) { + @media (width >= 640px) { h1 { font-size: 1.875rem; line-height: 2.25rem; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { h1 { font-size: 1.5rem; line-height: 2rem; @@ -415,13 +406,13 @@ test('@apply', () => { font-size: 1.5rem; line-height: 2rem; } - @media (min-width: 1024px) { + @media (width >= 1024px) { h2 { font-size: 1.5rem; line-height: 2rem; } } - @media (min-width: 640px) { + @media (width >= 640px) { h2 { font-size: 1.5rem; line-height: 2rem; @@ -710,27 +701,27 @@ test('@applying classes from outside a @layer respects the source order', async .container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -1442,10 +1433,8 @@ describe('multiple instances', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .a { - color: red; - --tw-text-opacity: 1; - color: rgb(34 197 94 / var(--tw-text-opacity)); color: #00f; + --tw-text-opacity: 1; text-decoration: underline; } .b { @@ -1478,13 +1467,13 @@ describe('multiple instances', () => { font-size: 1.25rem; line-height: 1.75rem; } - @media (min-width: 1024px) { + @media (width >= 1024px) { h2 { font-size: 1.875rem; line-height: 2.25rem; } } - @media (min-width: 640px) { + @media (width >= 640px) { h2 { font-size: 1.5rem; line-height: 2rem; @@ -1683,7 +1672,6 @@ it('should be possible to use apply in plugins', async () => { color: red; } .b { - color: red; color: #00f; } `) @@ -1754,7 +1742,7 @@ it('apply + layer utilities + selector variants (like group) + important selecto let result = await run(input, config) expect(result.css).toMatchFormattedCss(css` - #myselector :is(.custom-utility) { + #myselector .custom-utility { font-weight: 400; } #myselector :is(.group:hover .custom-utility) { @@ -1883,17 +1871,14 @@ it('can apply joined classes when using elements', async () => { .bar.foo { color: green; } - header:nth-of-type(2n + 1).bar { + header:nth-of-type(odd).bar { color: red; } - header.bar:nth-of-type(2n + 1) { - color: green; - } + header.bar:nth-of-type(odd), header.bar:after, main.bar, main.foo, footer.foo { - color: red; color: green; } `) @@ -2031,9 +2016,9 @@ it('pseudo elements inside apply are moved outside of :is() or :has()', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - :is(.dark .foo)::before, - :is([dir='rtl'] :is(.dark .bar))::before, - :is([dir='rtl'] :is(.dark .baz:hover))::before { + :is(.dark .foo):before, + :is([dir='rtl'] :is(.dark .bar)):before, + :is([dir='rtl'] :is(.dark .baz:hover)):before { background-color: #000; } :is([dir='rtl'] :is(.dark .qux))::file-selector-button:hover { @@ -2055,7 +2040,7 @@ it('pseudo elements inside apply are moved outside of :is() or :has()', () => { }) }) -test.skip('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => { +test('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => { let config = { darkMode: 'class', content: [ @@ -2079,22 +2064,11 @@ test.skip('::ng-deep, ::deep, ::v-deep pseudo elements are left alone', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - ::ng-deep .foo .bar { - font-weight: 700; - } - ::v-deep .foo .bar { - font-weight: 700; - } + ::ng-deep .foo .bar, + ::v-deep .foo .bar, ::deep .foo .bar { font-weight: 700; } `) }) }) - -// TODO: Oxide -// 1. `::ng-deep` is deprecated -// 2. `::deep` and `::v-deep` are non-standard -// 3. They all use invalid selector syntax that Lightning CSS does not support -// It may be enough for Oxide to not support it at all -test.todo('::ng-deep, ::deep, ::v-deep pseudo elements are left alone') diff --git a/tests/arbitrary-properties.test.js b/tests/arbitrary-properties.test.js index 17f0bcf1f..c9ae197b9 100644 --- a/tests/arbitrary-properties.test.js +++ b/tests/arbitrary-properties.test.js @@ -75,7 +75,7 @@ test('arbitrary properties with modifiers', () => { expect(result.css).toMatchFormattedCss(css` ${defaults} @media (prefers-color-scheme: dark) { - @media (min-width: 1024px) { + @media (width >= 1024px) { .dark\:lg\:hover\:\[paint-order\:markers\]:hover { paint-order: markers; } diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index 32646e5ff..3b70e9363 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -185,7 +185,7 @@ min-width: 3.23rem; } .min-w-\[calc\(1-\(\(12-3\)\*0\.5\)\)\] { - min-width: -3.5px; + min-width: -3.5; } .min-w-\[calc\(1-\(var\(--something\)\*0\.5\)\)\] { min-width: calc(1 - (var(--something) * 0.5)); @@ -682,7 +682,7 @@ background-image: linear-gradient(to left, rgb(var(--green)), blue); } .bg-\[repeating-conic-gradient\(\#F8F9FA_0\%_25\%\,_white_0\%_50\%\)\] { - background-image: repeating-conic-gradient(#f8f9fa 0% 25%, white 0% 50%); + background-image: repeating-conic-gradient(#f8f9fa 0% 25%, #fff 0% 50%); } .bg-\[url\(\'\/path-to-image\.png\'\)\] { background-image: url('/path-to-image.png'); @@ -1110,7 +1110,7 @@ --tw-content: attr(content-before); content: var(--tw-content); } -@media (min-width: 1024px) { +@media (width >= 1024px) { .lg\:grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; } diff --git a/tests/arbitrary-values.test.js b/tests/arbitrary-values.test.js index 923607517..1949e863a 100644 --- a/tests/arbitrary-values.test.js +++ b/tests/arbitrary-values.test.js @@ -605,7 +605,7 @@ it('should support underscores in arbitrary modifiers', () => { return expect(result.css).toMatchFormattedCss(css` .text-lg\/\[calc\(50px_\*_2\)\] { font-size: 1.125rem; - line-height: calc(50px * 2); + line-height: 100px; } `) }) diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index c49376139..da69272f1 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -64,7 +64,7 @@ test('arbitrary variants with modifiers', () => { expect(result.css).toMatchFormattedCss(css` ${defaults} @media (prefers-color-scheme: dark) { - @media (min-width: 1024px) { + @media (width >= 1024px) { .dark\:lg\:hover\:\[\&\>\*\]\:underline > :hover { text-decoration-line: underline; } @@ -120,7 +120,7 @@ test('arbitrary variants are sorted after other variants', () => { .underline { text-decoration-line: underline; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .lg\:underline { text-decoration-line: underline; } @@ -1149,7 +1149,7 @@ it('should output responsive variants + stacked variants in the right order', () return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 1280px) { + @media (width >= 1280px) { .xl\:p-1 { padding: 0.25rem; } @@ -1160,7 +1160,7 @@ it('should output responsive variants + stacked variants in the right order', () .\[\&_ul\]\:flex-col ul { flex-direction: column; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:\[\&_ul\]\:flex-row ul { flex-direction: row; } diff --git a/tests/basic-usage.test.css b/tests/basic-usage.test.css index 80c406bf6..6efad7540 100644 --- a/tests/basic-usage.test.css +++ b/tests/basic-usage.test.css @@ -53,37 +53,37 @@ .container { width: 100%; } -@media (min-width: 640px) { +@media (width >= 640px) { .container { max-width: 640px; } } -@media (min-width: 768px) { +@media (width >= 768px) { .container { max-width: 768px; } } -@media (min-width: 1024px) { +@media (width >= 1024px) { .container { max-width: 1024px; } } -@media (min-width: 1280px) { +@media (width >= 1280px) { .container { max-width: 1280px; } } -@media (min-width: 1536px) { +@media (width >= 1536px) { .container { max-width: 1536px; } } .sr-only { - width: 1px; - height: 1px; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; + width: 1px; + height: 1px; margin: -1px; padding: 0; position: absolute; @@ -196,7 +196,7 @@ display: none; } .aspect-square { - aspect-ratio: 1 / 1; + aspect-ratio: 1; } .aspect-video { aspect-ratio: 16 / 9; diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index c34ba8aee..9115cacd0 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -457,9 +457,6 @@ it('does not produce duplicate output when seeing variants preceding a wildcard return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - * { - color: #00f; - } .combined, * { color: red; diff --git a/tests/blocklist.test.js b/tests/blocklist.test.js index e9915350f..78958ca0c 100644 --- a/tests/blocklist.test.js +++ b/tests/blocklist.test.js @@ -27,7 +27,7 @@ it('can block classes matched literally', () => { .my-custom-class { color: red; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:hover\:text-sm:hover { font-size: 0.875rem; line-height: 1.25rem; diff --git a/tests/collapse-adjacent-rules.test.js b/tests/collapse-adjacent-rules.test.js index 69c471686..b0f668157 100644 --- a/tests/collapse-adjacent-rules.test.js +++ b/tests/collapse-adjacent-rules.test.js @@ -106,7 +106,7 @@ test('collapse adjacent rules', () => { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .some-apply-thing { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); @@ -114,7 +114,7 @@ test('collapse adjacent rules', () => { } } @supports (foo: bar) { - @media (min-width: 768px) { + @media (width >= 768px) { .some-apply-thing { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); @@ -122,7 +122,7 @@ test('collapse adjacent rules', () => { } } } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:text-center { text-align: center; } @@ -130,7 +130,7 @@ test('collapse adjacent rules', () => { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:text-center { text-align: center; } @@ -138,7 +138,7 @@ test('collapse adjacent rules', () => { font-weight: 700; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .lg\:text-center { text-align: center; } diff --git a/tests/collapse-duplicate-declarations.test.js b/tests/collapse-duplicate-declarations.test.js index dc8834b74..c75cc81dc 100644 --- a/tests/collapse-duplicate-declarations.test.js +++ b/tests/collapse-duplicate-declarations.test.js @@ -75,7 +75,6 @@ it('should not collapse duplicate declarations with the different units', () => return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .example { - height: 100px; height: 50%; } `) @@ -107,8 +106,6 @@ it('should collapse the duplicate declarations with the same unit, but leave the return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .example { - height: 200px; - height: 100%; height: 30vh; } `) @@ -166,8 +163,6 @@ it('should work on a real world example', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .h-available { - height: 100%; - height: 100vh; height: -webkit-fill-available; } `) diff --git a/tests/containerPlugin.test.js b/tests/containerPlugin.test.js index 4b334e90c..8db24fe8a 100644 --- a/tests/containerPlugin.test.js +++ b/tests/containerPlugin.test.js @@ -8,27 +8,27 @@ test('options are not required', () => { .container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -52,12 +52,12 @@ test('screens can be passed explicitly', () => { .container { width: 100%; } - @media (min-width: 400px) { + @media (width >= 400px) { .container { max-width: 400px; } } - @media (min-width: 500px) { + @media (width >= 500px) { .container { max-width: 500px; } @@ -81,12 +81,12 @@ test('screens are ordered ascending by min-width', () => { .container { width: 100%; } - @media (min-width: 400px) { + @media (width >= 400px) { .container { max-width: 400px; } } - @media (min-width: 500px) { + @media (width >= 500px) { .container { max-width: 500px; } @@ -114,12 +114,12 @@ test('screens are deduplicated by min-width', () => { .container { width: 100%; } - @media (min-width: 576px) { + @media (width >= 576px) { .container { max-width: 576px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } @@ -145,27 +145,27 @@ test('the container can be centered by default', () => { margin-left: auto; margin-right: auto; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -191,27 +191,27 @@ test('horizontal padding can be included by default', () => { padding-left: 2rem; padding-right: 2rem; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -248,26 +248,26 @@ test('responsive horizontal padding can be included by default', () => { padding-left: 1rem; padding-right: 1rem; } - @media (min-width: 576px) { + @media (width >= 576px) { .container { max-width: 576px; padding-left: 2rem; padding-right: 2rem; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 992px) { + @media (width >= 992px) { .container { max-width: 992px; padding-left: 4rem; padding-right: 4rem; } } - @media (min-width: 1200px) { + @media (width >= 1200px) { .container { max-width: 1200px; padding-left: 5rem; @@ -299,12 +299,12 @@ test('setting all options at once', () => { padding-left: 2rem; padding-right: 2rem; } - @media (min-width: 400px) { + @media (width >= 400px) { .container { max-width: 400px; } } - @media (min-width: 500px) { + @media (width >= 500px) { .container { max-width: 500px; } @@ -325,16 +325,16 @@ test('container can use variants', () => { return run('@tailwind components', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 1024px) { + @media (width >= 1024px) { .lg\:hover\:container:hover { width: 100%; } - @media (min-width: 400px) { + @media (width >= 400px) { .lg\:hover\:container:hover { max-width: 400px; } } - @media (min-width: 500px) { + @media (width >= 500px) { .lg\:hover\:container:hover { max-width: 500px; } diff --git a/tests/custom-plugins.test.js b/tests/custom-plugins.test.js index 0f45e9823..2c754d231 100644 --- a/tests/custom-plugins.test.js +++ b/tests/custom-plugins.test.js @@ -436,17 +436,17 @@ test('plugins can create components with media queries with object syntax', () = .custom-container { width: 100%; } - @media (min-width: 100px) { + @media (width >= 100px) { .custom-container { max-width: 100px; } } - @media (min-width: 200px) { + @media (width >= 200px) { .custom-container { max-width: 200px; } } - @media (min-width: 300px) { + @media (width >= 300px) { .custom-container { max-width: 300px; } @@ -497,7 +497,7 @@ test('media queries can be defined multiple times using objects-in-array syntax' .custom-container { width: 100%; } - @media (min-width: 100px) { + @media (width >= 100px) { .custom-container { max-width: 100px; } @@ -506,7 +506,7 @@ test('media queries can be defined multiple times using objects-in-array syntax' padding: 1rem 0.5rem; display: block; } - @media (min-width: 100px) { + @media (width >= 100px) { .btn { display: inline-block; } @@ -557,7 +557,7 @@ test('plugins can create nested rules', () => { .btn-blue:hover { background-color: #00008b; } - @media (min-width: 500px) { + @media (width >= 500px) { .btn-blue:hover { background-color: orange; } @@ -634,22 +634,22 @@ test('plugins can access the current config', () => { .custom-container { width: 100%; } - @media (min-width: 576px) { + @media (width >= 576px) { .custom-container { max-width: 576px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .custom-container { max-width: 768px; } } - @media (min-width: 992px) { + @media (width >= 992px) { .custom-container { max-width: 992px; } } - @media (min-width: 1200px) { + @media (width >= 1200px) { .custom-container { max-width: 1200px; } @@ -1254,7 +1254,7 @@ test('plugins can be created using the `createPlugin` function', () => { .hover\:test-sm:hover { test-property: 1rem; } - @media (min-width: 400px) { + @media (width >= 400px) { .sm\:test-sm { test-property: 1rem; } @@ -1319,7 +1319,7 @@ test('plugins with extra options can be created using the `createPlugin.withOpti .hover\:banana-sm:hover { test-property: 1rem; } - @media (min-width: 400px) { + @media (width >= 400px) { .sm\:banana-sm { test-property: 1rem; } @@ -1356,7 +1356,7 @@ test('plugins should cache correctly', () => { .banana { position: absolute; } - @media (min-width: 400px) { + @media (width >= 400px) { .sm\:banana { position: absolute; } @@ -1367,15 +1367,15 @@ test('plugins should cache correctly', () => { .apple { position: absolute; } - @media (min-width: 400px) { + @media (width >= 400px) { .sm\:apple { position: absolute; } } ` - expect(result1.css).toMatchCss(expected1) - expect(result2.css).toMatchCss(expected2) + expect(result1.css).toMatchFormattedCss(expected1) + expect(result2.css).toMatchFormattedCss(expected2) } ) }) @@ -1436,7 +1436,7 @@ test('plugins created using `createPlugin.withOptions` do not need to be invoked .hover\:banana-sm:hover { test-property: 1rem; } - @media (min-width: 400px) { + @media (width >= 400px) { .sm\:banana-sm { test-property: 1rem; } @@ -1493,7 +1493,7 @@ test('the configFunction parameter is optional when using the `createPlugin.with .hover\:banana-sm:hover { test-property: 1px; } - @media (min-width: 400px) { + @media (width >= 400px) { .sm\:banana-sm { test-property: 1px; } @@ -1534,7 +1534,7 @@ test('keyframes are not escaped', () => { .foo-\[abc\] { animation: 1s infinite abc; } - @media (min-width: 768px) { + @media (width >= 768px) { @keyframes def { 25.001% { color: #000; diff --git a/tests/custom-separator.test.js b/tests/custom-separator.test.js index 3b1708dfb..715238d64 100644 --- a/tests/custom-separator.test.js +++ b/tests/custom-separator.test.js @@ -33,7 +33,7 @@ test('custom separator', () => { :is(.dark .dark_focus_text-left:focus) { text-align: left; } - @media (min-width: 768px) { + @media (width >= 768px) { .md_hover_text-right:hover { text-align: right; } diff --git a/tests/customConfig.test.js b/tests/customConfig.test.js index b8f459144..e6c6f79ca 100644 --- a/tests/customConfig.test.js +++ b/tests/customConfig.test.js @@ -12,7 +12,7 @@ test('it uses the values from the custom config file', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } @@ -33,7 +33,7 @@ test('custom config can be passed as an object', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } @@ -49,7 +49,7 @@ test('custom config path can be passed using `config` property in an object', () return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } @@ -72,7 +72,7 @@ test('custom config can be passed under the `config` property', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } @@ -97,7 +97,7 @@ test('tailwind.config.cjs is picked up by default', () => { return run('@tailwind utilities').then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } @@ -123,7 +123,7 @@ test('tailwind.config.js is picked up by default', () => { return run('@tailwind utilities').then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } @@ -149,7 +149,7 @@ test('tailwind.config.cjs is picked up by default when passing an empty object', return run('@tailwind utilities', {}).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } @@ -175,7 +175,7 @@ test('tailwind.config.js is picked up by default when passing an empty object', return run('@tailwind utilities', {}).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 400px) { + @media (width >= 400px) { .mobile\:font-bold { font-weight: 700; } diff --git a/tests/detect-nesting.test.js b/tests/detect-nesting.test.js index 08eeacf98..555a80129 100644 --- a/tests/detect-nesting.test.js +++ b/tests/detect-nesting.test.js @@ -88,7 +88,7 @@ it('should not warn when nesting a single rule inside a media query', () => { let input = css` @tailwind utilities; - @media (min-width: 768px) { + @media (width >= 768px) { .nested { } } diff --git a/tests/evaluateTailwindFunctions.test.js b/tests/evaluateTailwindFunctions.test.js index 52f1fed07..e6bf124b6 100644 --- a/tests/evaluateTailwindFunctions.test.js +++ b/tests/evaluateTailwindFunctions.test.js @@ -559,7 +559,7 @@ test('font sizes are retrieved without default line-heights or letter-spacing', }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -571,12 +571,6 @@ test('outlines are retrieved without default outline-offset', () => { } ` - let output = css` - .element { - outline: 2px dotted #000; - } - ` - return run(input, { theme: { outline: { @@ -584,7 +578,11 @@ test('outlines are retrieved without default outline-offset', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + .element { + outline: 2px dotted black; + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -623,7 +621,7 @@ test('font-family values are retrieved without font-variation-settings', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -650,7 +648,7 @@ test('font-variation-settings values can be retrieved', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -675,7 +673,7 @@ test('font-family values are joined when an array', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -714,7 +712,7 @@ test('font-family values are retrieved without font-feature-settings', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -727,13 +725,6 @@ test('font-feature-settings values can be retrieved', () => { } ` - let output = css` - .heading { - font-feature-settings: 'cv11'; - font-family: Inter; - } - ` - return run(input, { theme: { fontFamily: { @@ -741,7 +732,12 @@ test('font-feature-settings values can be retrieved', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + .heading { + font-family: Inter; + font-feature-settings: 'cv11'; + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -753,12 +749,6 @@ test('box-shadow values are joined when an array', () => { } ` - let output = css` - .element { - box-shadow: 0 0 2px #000, 1px 2px 3px #fff; - } - ` - return run(input, { theme: { boxShadow: { @@ -766,7 +756,11 @@ test('box-shadow values are joined when an array', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + .element { + box-shadow: 0 0 2px black, 1px 2px 3px white; + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -791,7 +785,7 @@ test('transition-property values are joined when an array', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -816,7 +810,7 @@ test('transition-duration values are joined when an array', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -830,18 +824,16 @@ test('basic screen function calls are expanded', () => { } ` - let output = css` - @media (min-width: 600px) { - .foo { - color: red; - } - } - ` - return run(input, { theme: { screens: { sm: '600px' } }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 600px) { + .foo { + color: red; + } + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -866,7 +858,7 @@ test('screen function supports max-width screens', () => { return run(input, { theme: { screens: { sm: { max: '600px' } } }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -880,18 +872,16 @@ test('screen function supports min-width screens', () => { } ` - let output = css` - @media (min-width: 600px) { - .foo { - color: red; - } - } - ` - return run(input, { theme: { screens: { sm: { min: '600px' } } }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 600px) { + .foo { + color: red; + } + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -905,18 +895,16 @@ test('screen function supports min-width and max-width screens', () => { } ` - let output = css` - @media (min-width: 600px) and (max-width: 700px) { - .foo { - color: red; - } - } - ` - return run(input, { theme: { screens: { sm: { min: '600px', max: '700px' } } }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 600px) and (max-width: 700px) { + .foo { + color: red; + } + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -941,7 +929,7 @@ test('screen function supports raw screens', () => { return run(input, { theme: { screens: { mono: { raw: 'monochrome' } } }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -955,18 +943,16 @@ test('screen arguments can be quoted', () => { } ` - let output = css` - @media (min-width: 600px) { - .foo { - color: red; - } - } - ` - return run(input, { theme: { screens: { sm: '600px' } }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + @media (min-width: 600px) { + .foo { + color: red; + } + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -978,18 +964,16 @@ test('Theme function can extract alpha values for colors (1)', () => { } ` - let output = css` - .foo { - color: #3b82f680; - } - ` - return run(input, { theme: { colors: { blue: { 500: '#3b82f6' } }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + .foo { + color: rgb(59 130 246 / 50%); + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -1001,18 +985,16 @@ test('Theme function can extract alpha values for colors (2)', () => { } ` - let output = css` - .foo { - color: #3b82f680; - } - ` - return run(input, { theme: { colors: { blue: { 500: '#3b82f6' } }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + .foo { + color: rgb(59 130 246 / 0.5); + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -1035,7 +1017,7 @@ test('Theme function can extract alpha values for colors (3)', () => { colors: { blue: { 500: '#3b82f6' } }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1047,12 +1029,6 @@ test('Theme function can extract alpha values for colors (4)', () => { } ` - let output = css` - .foo { - color: #3c83f680; - } - ` - return run(input, { theme: { colors: { @@ -1060,7 +1036,11 @@ test('Theme function can extract alpha values for colors (4)', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + .foo { + color: hsl(217 91% 60% / 50%); + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -1072,12 +1052,6 @@ test('Theme function can extract alpha values for colors (5)', () => { } ` - let output = css` - .foo { - color: #3c83f680; - } - ` - return run(input, { theme: { colors: { @@ -1085,7 +1059,11 @@ test('Theme function can extract alpha values for colors (5)', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(css` + .foo { + color: hsl(217 91% 60% / 0.5); + } + `) expect(result.warnings().length).toBe(0) }) }) @@ -1110,7 +1088,7 @@ test('Theme function can extract alpha values for colors (6)', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1137,7 +1115,7 @@ test('Theme function can extract alpha values for colors (7)', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1168,7 +1146,7 @@ test('Theme function can extract alpha values for colors (8)', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1198,7 +1176,7 @@ test('Theme functions replace the alpha value placeholder even with no alpha pro }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1229,7 +1207,7 @@ test('Theme functions can reference values with slashes in brackets', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1254,7 +1232,7 @@ test('Theme functions with alpha value inside quotes', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1279,7 +1257,7 @@ test('Theme functions with alpha with quotes value around color only', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) @@ -1312,7 +1290,7 @@ it('can find values with slashes in the theme key while still allowing for alpha }, }, }).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .foo00 { color: #050000; } @@ -1358,7 +1336,7 @@ describe('context dependent', () => { let result = await runFull('@tailwind utilities', configPath) // 1. On first run it should work because it's been removed from the class cache - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .underline { text-decoration-line: underline; } @@ -1370,7 +1348,7 @@ describe('context dependent', () => { // 3. The second run should work fine because it's been removed from the class cache result = await runFull('@tailwind utilities', configPath) - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .underline { text-decoration-line: underline; } @@ -1406,7 +1384,7 @@ describe('context dependent', () => { }, }, }).then((result) => { - expect(result.css).toMatchCss(output) + expect(result.css).toMatchFormattedCss(output) expect(result.warnings().length).toBe(0) }) }) diff --git a/tests/experimental.test.js b/tests/experimental.test.js index b3fa49185..b36141cb0 100644 --- a/tests/experimental.test.js +++ b/tests/experimental.test.js @@ -13,7 +13,7 @@ test('experimental universal selector improvements (box-shadow)', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .shadow { --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; @@ -47,7 +47,7 @@ test('experimental universal selector improvements (pseudo hover)', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .hover\:shadow { --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; @@ -81,7 +81,7 @@ test('experimental universal selector improvements (multiple classes: group)', ( ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .group-hover\:shadow { --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; @@ -115,7 +115,7 @@ test('experimental universal selector improvements (child selectors: divide-y)', ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .resize { resize: both; } @@ -141,7 +141,7 @@ test('experimental universal selector improvements (hover:divide-y)', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .resize { resize: both; } @@ -168,14 +168,14 @@ test('experimental universal selector improvements (#app important)', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .shadow { --tw-ring-offset-shadow: 0 0 #0000; --tw-ring-shadow: 0 0 #0000; --tw-shadow: 0 0 #0000; --tw-shadow-colored: 0 0 #0000; } - #app :is(.resize) { + #app .resize { resize: both; } #app :is(.divide-y > :not([hidden]) ~ :not([hidden])) { @@ -183,7 +183,7 @@ test('experimental universal selector improvements (#app important)', () => { border-top-width: calc(1px * calc(1 - var(--tw-divide-y-reverse))); border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } - #app :is(.shadow) { + #app .shadow { --tw-shadow: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); diff --git a/tests/import-syntax.test.js b/tests/import-syntax.test.js index 99f5163f7..a089cb955 100644 --- a/tests/import-syntax.test.js +++ b/tests/import-syntax.test.js @@ -40,27 +40,27 @@ test('using @import instead of @tailwind', () => { .container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -72,7 +72,7 @@ test('using @import instead of @tailwind', () => { --tw-bg-opacity: 1; background-color: rgb(0 0 0 / var(--tw-bg-opacity)); } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:hover\:text-center:hover { text-align: center; } diff --git a/tests/important-boolean.test.js b/tests/important-boolean.test.js index d66f21edc..de1eb3e3e 100644 --- a/tests/important-boolean.test.js +++ b/tests/important-boolean.test.js @@ -80,27 +80,27 @@ test('important boolean', () => { .container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -148,7 +148,7 @@ test('important boolean', () => { :is(.dark .dark\:focus\:text-left:focus) { text-align: left !important; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:hover\:text-right:hover { text-align: right !important; } diff --git a/tests/important-modifier-prefix.test.js b/tests/important-modifier-prefix.test.js index 2c6a8bb62..370c09dc2 100644 --- a/tests/important-modifier-prefix.test.js +++ b/tests/important-modifier-prefix.test.js @@ -31,27 +31,27 @@ test('important modifier with prefix', () => { .\!tw-container { width: 100% !important; } - @media (min-width: 640px) { + @media (width >= 640px) { .\!tw-container { max-width: 640px !important; } } - @media (min-width: 768px) { + @media (width >= 768px) { .\!tw-container { max-width: 768px !important; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .\!tw-container { max-width: 1024px !important; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .\!tw-container { max-width: 1280px !important; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .\!tw-container { max-width: 1536px !important; } @@ -62,12 +62,12 @@ test('important modifier with prefix', () => { .hover\:\!tw-text-center:hover { text-align: center !important; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .lg\:\!tw-opacity-50 { opacity: 0.5 !important; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .xl\:focus\:disabled\:\!tw-float-right:disabled:focus { float: right !important; } diff --git a/tests/important-modifier.test.js b/tests/important-modifier.test.js index c736951d0..44b07fbfd 100644 --- a/tests/important-modifier.test.js +++ b/tests/important-modifier.test.js @@ -53,27 +53,27 @@ test('important modifier', () => { .\!container { width: 100% !important; } - @media (min-width: 640px) { + @media (width >= 640px) { .\!container { max-width: 640px !important; } } - @media (min-width: 768px) { + @media (width >= 768px) { .\!container { max-width: 768px !important; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .\!container { max-width: 1024px !important; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .\!container { max-width: 1280px !important; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .\!container { max-width: 1536px !important; } @@ -94,12 +94,12 @@ test('important modifier', () => { .hover\:\!text-center:hover { text-align: center !important; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .lg\:\!opacity-50 { opacity: 0.5 !important; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .xl\:focus\:disabled\:\!float-right:disabled:focus { float: right !important; } @@ -137,9 +137,7 @@ test('the important modifier works on utilities using :where()', () => { :where(.\!btn) { background-color: #00f !important; } - :where(.btn) { - background-color: #00f; - } + :where(.btn), :where(.hover\:btn:hover) { background-color: #00f; } diff --git a/tests/important-selector.test.js b/tests/important-selector.test.js index a5399bdf7..b9dc92b3a 100644 --- a/tests/important-selector.test.js +++ b/tests/important-selector.test.js @@ -78,27 +78,27 @@ test('important selector', () => { .container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -123,10 +123,10 @@ test('important selector', () => { transform: rotate(360deg); } } - #app :is(.animate-spin) { + #app .animate-spin { animation: 1s linear infinite spin; } - #app :is(.font-bold) { + #app .font-bold { font-weight: 700; } .custom-util { @@ -135,11 +135,11 @@ test('important selector', () => { #app :is(.group:hover .group-hover\:focus-within\:text-left:focus-within) { text-align: left; } - #app :is(:is([dir='rtl'] .rtl\:active\:text-center:active)) { + #app :is([dir='rtl'] .rtl\:active\:text-center:active) { text-align: center; } @media (prefers-reduced-motion: no-preference) { - #app :is(.motion-safe\:hover\:text-center:hover) { + #app .motion-safe\:hover\:text-center:hover { text-align: center; } } @@ -147,11 +147,11 @@ test('important selector', () => { content: var(--tw-content); text-decoration-line: underline; } - #app :is(:is(.dark .dark\:focus\:text-left:focus)) { + #app :is(.dark .dark\:focus\:text-left:focus) { text-align: left; } - @media (min-width: 768px) { - #app :is(.md\:hover\:text-right:hover) { + @media (width >= 768px) { + #app .md\:hover\:text-right:hover { text-align: right; } } @@ -186,7 +186,7 @@ test('pseudo-elements are appended after the `:is()`', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` ${defaults} - #app :is(.dark .dark\:before\:flex)::before { + #app :is(.dark .dark\:before\:flex):before { content: var(--tw-content); display: flex; } diff --git a/tests/kitchen-sink.test.js b/tests/kitchen-sink.test.js index 8f4b7cae2..2763db668 100644 --- a/tests/kitchen-sink.test.js +++ b/tests/kitchen-sink.test.js @@ -243,7 +243,7 @@ test('it works', () => { Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .screen-test { color: purple; } @@ -261,7 +261,7 @@ test('it works', () => { .apply-test:hover:focus { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .apply-test { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); @@ -274,27 +274,27 @@ test('it works', () => { .apply-components { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .apply-components { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .apply-components { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .apply-components { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .apply-components { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .apply-components { max-width: 1536px; } @@ -311,7 +311,7 @@ test('it works', () => { .apply-with-existing:hover { font-weight: 400; } - @media (min-width: 640px) { + @media (width >= 640px) { .apply-with-existing:hover { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); @@ -344,7 +344,7 @@ test('it works', () => { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } - @media (min-width: 640px) { + @media (width >= 640px) { @media (prefers-reduced-motion: no-preference) { .group:active .crazy-example:focus { opacity: 0.1; @@ -365,27 +365,27 @@ test('it works', () => { .container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .container { max-width: 1536px; } @@ -580,86 +580,86 @@ test('it works', () => { .hover\:container:hover { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .hover\:container:hover { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .hover\:container:hover { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .hover\:container:hover { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .hover\:container:hover { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .hover\:container:hover { max-width: 1536px; } } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .sm\:container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .sm\:container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .sm\:container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .sm\:container { max-width: 1536px; } } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .md\:container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .md\:container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .md\:container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .md\:container { max-width: 1536px; } @@ -743,7 +743,7 @@ test('it works', () => { :is(.dark .dark\:custom-util) { background: #abcdef; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:text-center { text-align: center; } @@ -761,7 +761,7 @@ test('it works', () => { } } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:text-center { text-align: center; } @@ -791,18 +791,18 @@ test('it works', () => { background: #abcdef !important; } } - @media (min-width: 640px) { + @media (width >= 640px) { .md\:sm\:text-center { text-align: center; } } } - @media (min-width: 1280px) and (max-width: 1535px) { + @media (width >= 1280px) and (width <= 1535px) { .range\:text-right { text-align: right; } } - @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { + @media (width >= 640px) and (width <= 767px), (width <= 868px) { .multi\:text-left { text-align: left; } diff --git a/tests/match-utilities.test.js b/tests/match-utilities.test.js index 41ef29a29..a9705b021 100644 --- a/tests/match-utilities.test.js +++ b/tests/match-utilities.test.js @@ -194,7 +194,7 @@ test('matching utilities with a basic configured value', () => { } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-foo { value: value_foo; } @@ -224,7 +224,7 @@ test('matching utilities with an arbitrary value and configured modifier', () => } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-\[foo\]\/bar { value: foo; modifier: configured_bar; @@ -256,7 +256,7 @@ test('matching utilities with an configured value and an arbitrary modifier (raw } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-foo\/\[bar\] { value: configured_foo; modifier: [bar]; @@ -288,7 +288,7 @@ test('matching utilities with an configured value and an arbitrary modifier (non } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-foo\/\[bar\] { value: configured_foo; modifier: bar; @@ -322,7 +322,7 @@ test('matching utilities with an configured value and a configured modifier', () } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-foo\/bar { value: configured_foo; modifier: configured_bar; @@ -351,7 +351,7 @@ test('matching utilities with an arbitrary value and an arbitrary modifier (raw) } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-\[foo\]\/\[bar\] { value: foo; modifier: [bar]; @@ -380,7 +380,7 @@ test('matching utilities with an arbitrary value and an arbitrary modifier (non- } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-\[foo\]\/\[bar\] { value: foo; modifier: bar; @@ -411,7 +411,7 @@ test('matching utilities with a lookup value that looks like an arbitrary value } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-\[foo\]\/\[bar\] { value: hello; } @@ -442,7 +442,7 @@ test('matching utilities with a lookup value that looks like an arbitrary value } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-\[foo\]\/\[bar\] { value: hello; } @@ -473,7 +473,7 @@ test('matching utilities with a lookup value that looks like an arbitrary value } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-\[foo\]\/\[bar\] { value: hello; } @@ -503,7 +503,7 @@ test('matching utilities with a lookup value that looks like an arbitrary value } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-\[foo\]\/bar { value: hello; } @@ -533,7 +533,7 @@ test('matching utilities with a lookup value that looks like a configured value } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-foo\/\[bar\] { value: hello; } @@ -564,7 +564,7 @@ test('matching utilities with a lookup value that does not match the configured } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .test-foo { value: not-a-percentage; } diff --git a/tests/match-variants.test.js b/tests/match-variants.test.js index 2923b10c0..0c9034eee 100644 --- a/tests/match-variants.test.js +++ b/tests/match-variants.test.js @@ -244,12 +244,12 @@ it('should be possible to sort variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { + @media (width >= 500px) { .testmin-\[500px\]\:underline { text-decoration-line: underline; } } - @media (min-width: 700px) { + @media (width >= 700px) { .testmin-\[700px\]\:italic { font-style: italic; } @@ -290,17 +290,17 @@ it('should be possible to compare arbitrary variants and hardcoded variants', () return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 500px) { + @media (width >= 500px) { .testmin-\[500px\]\:italic { font-style: italic; } } - @media (min-width: 600px) { + @media (width >= 600px) { .testmin-example\:italic { font-style: italic; } } - @media (min-width: 700px) { + @media (width >= 700px) { .testmin-\[700px\]\:italic { font-style: italic; } @@ -351,25 +351,25 @@ it('should be possible to sort stacked arbitrary variants correctly', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 400px) { + @media (width >= 100px) { + @media (width <= 400px) { .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (max-width: 350px) { + @media (width <= 350px) { .testmin-\[100px\]\:testmax-\[350px\]\:underline { text-decoration-line: underline; } } - @media (max-width: 300px) { + @media (width <= 300px) { .testmin-\[100px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } } } - @media (min-width: 150px) { - @media (max-width: 400px) { + @media (width >= 150px) { + @media (width <= 400px) { .testmin-\[150px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } @@ -415,8 +415,8 @@ it('should maintain sort from other variants, if sort functions of arbitrary var return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 200px) { + @media (width >= 100px) { + @media (width <= 200px) { .testmin-\[100px\]\:testmax-\[200px\]\:hover\:underline:hover, .testmin-\[100px\]\:testmax-\[200px\]\:focus\:underline:focus { text-decoration-line: underline; @@ -464,25 +464,25 @@ it('should sort arbitrary variants left to right (1)', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 400px) { + @media (width >= 100px) { + @media (width <= 400px) { .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (max-width: 300px) { + @media (width <= 300px) { .testmin-\[100px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } } } - @media (min-width: 200px) { - @media (max-width: 400px) { + @media (width >= 200px) { + @media (width <= 400px) { .testmin-\[200px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (max-width: 300px) { + @media (width <= 300px) { .testmin-\[200px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } @@ -529,26 +529,26 @@ it('should sort arbitrary variants left to right (2)', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (max-width: 400px) { - @media (min-width: 100px) { + @media (width <= 400px) { + @media (width >= 100px) { .testmax-\[400px\]\:testmin-\[100px\]\:underline { text-decoration-line: underline; } } - @media (min-width: 200px) { + @media (width >= 200px) { .testmax-\[400px\]\:testmin-\[200px\]\:underline { text-decoration-line: underline; } } } - @media (max-width: 300px) { - @media (min-width: 100px) { + @media (width <= 300px) { + @media (width >= 100px) { .testmax-\[300px\]\:testmin-\[100px\]\:underline { text-decoration-line: underline; } } - @media (min-width: 200px) { + @media (width >= 200px) { .testmax-\[300px\]\:testmin-\[200px\]\:underline { text-decoration-line: underline; } @@ -603,28 +603,28 @@ it('should guarantee that we are not passing values from other variants to the w return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 100px) { - @media (max-width: 400px) { + @media (width >= 100px) { + @media (width <= 400px) { .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (max-width: 300px) { + @media (width <= 300px) { .testmin-\[100px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } } } - @media (min-width: 200px) { - @media (max-width: 400px) { + @media (width >= 200px) { + @media (width <= 400px) { .testmin-\[200px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (max-width: 300px) { + @media (width <= 300px) { .testmin-\[200px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } diff --git a/tests/min-max-screen-variants.test.js b/tests/min-max-screen-variants.test.js index beab47ac0..b6ea5d254 100644 --- a/tests/min-max-screen-variants.test.js +++ b/tests/min-max-screen-variants.test.js @@ -34,32 +34,32 @@ it('sorts min and max correctly relative to screens and each other', async () => .font-bold { font-weight: 700; } - @media (max-width: 800px) { + @media (width <= 800px) { .max-\[800px\]\:font-bold { font-weight: 700; } } - @media (max-width: 700px) { + @media (width <= 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 700px) { + @media (width >= 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } } - @media (min-width: 800px) { + @media (width >= 800px) { .min-\[800px\]\:font-bold { font-weight: 700; } @@ -95,12 +95,12 @@ it('works when using min variants screens config is empty and variants all use t .font-bold { font-weight: 700; } - @media (min-width: 700px) { + @media (width >= 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } - @media (min-width: 800px) { + @media (width >= 800px) { .min-\[800px\]\:font-bold { font-weight: 700; } @@ -136,12 +136,12 @@ it('works when using max variants screens config is empty and variants all use t .font-bold { font-weight: 700; } - @media (max-width: 800px) { + @media (width <= 800px) { .max-\[800px\]\:font-bold { font-weight: 700; } } - @media (max-width: 700px) { + @media (width <= 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } @@ -176,32 +176,32 @@ it('converts simple min-width screens for max variant', () => { .font-bold { font-weight: 700; } - @media not all and (min-width: 1024px) { + @media not all and (width >= 1024px) { .max-lg\:font-bold { font-weight: 700; } } - @media (max-width: 700px) { + @media (width <= 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } } - @media not all and (min-width: 640px) { + @media not all and (width >= 640px) { .max-sm\:font-bold { font-weight: 700; } } - @media (max-width: 300px) { + @media (width <= 300px) { .max-\[300px\]\:font-bold { font-weight: 700; } } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } @@ -236,22 +236,22 @@ it('does not have keyed screens for min variant', () => { .font-bold { font-weight: 700; } - @media (min-width: 300px) { + @media (width >= 300px) { .min-\[300px\]\:font-bold { font-weight: 700; } } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 700px) { + @media (width >= 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } @@ -292,12 +292,12 @@ it('warns when using min variants with complex screen configs', async () => { .font-bold { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } @@ -336,12 +336,12 @@ it('warns when using min variants with simple configs containing mixed units', a .font-bold { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 48rem) { + @media (width >= 48rem) { .md\:font-bold { font-weight: 700; } @@ -380,12 +380,12 @@ it('warns when using min variants with mixed units (with screens config)', async .font-bold { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } @@ -422,7 +422,7 @@ it('warns when using min variants with mixed units (with no screens config)', as .font-bold { font-weight: 700; } - @media (min-width: 700px) { + @media (width >= 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } @@ -464,12 +464,12 @@ it('warns when using max variants with complex screen configs', async () => { .font-bold { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } @@ -508,12 +508,12 @@ it('warns when using max variants with simple configs containing mixed units', a .font-bold { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 48rem) { + @media (width >= 48rem) { .md\:font-bold { font-weight: 700; } @@ -552,12 +552,12 @@ it('warns when using max variants with mixed units (with screens config)', async .font-bold { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } @@ -594,7 +594,7 @@ it('warns when using max variants with mixed units (with no screens config)', as .font-bold { font-weight: 700; } - @media (max-width: 700px) { + @media (width <= 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } @@ -631,7 +631,7 @@ it('warns when using min and max variants with mixed units (with no screens conf .font-bold { font-weight: 700; } - @media (max-width: 700rem) { + @media (width <= 700rem) { .max-\[700rem\]\:font-bold { font-weight: 700; } diff --git a/tests/modify-selectors.test.js b/tests/modify-selectors.test.js index e6ce3cf14..aef52b8a4 100644 --- a/tests/modify-selectors.test.js +++ b/tests/modify-selectors.test.js @@ -69,7 +69,7 @@ test('modify selectors', () => { .foo .foo\:visited\:markdown:visited > p { margin-top: 12px; } - @media (min-width: 1024px) { + @media (width >= 1024px) { .foo .lg\:foo\:disabled\:markdown:disabled > p { margin-top: 12px; } @@ -78,12 +78,12 @@ test('modify selectors', () => { .foo .foo\:hover\:font-bold:hover { font-weight: 700; } - @media (min-width: 640px) { + @media (width >= 640px) { .foo .sm\:foo\:font-bold { font-weight: 700; } } - @media (min-width: 768px) { + @media (width >= 768px) { .foo .md\:foo\:focus\:font-bold:focus { font-weight: 700; } diff --git a/tests/negative-prefix.test.js b/tests/negative-prefix.test.js index 8b4949b1a..615558807 100644 --- a/tests/negative-prefix.test.js +++ b/tests/negative-prefix.test.js @@ -12,7 +12,7 @@ test('using a negative prefix with a negative scale value', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-2 { margin-top: -4px; } @@ -34,7 +34,7 @@ test('using a negative scale value with a plugin that does not support dynamic n } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-opacity-50 { opacity: 0.5; } @@ -53,7 +53,7 @@ test('using a negative prefix without a negative scale value', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-5 { margin-top: -20px; } @@ -75,7 +75,7 @@ test('being an asshole', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-\[10px\] { margin-top: 55px; } @@ -94,7 +94,7 @@ test('being a real asshole', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-\[10px\] { margin-top: -55px; } @@ -113,7 +113,7 @@ test('a value that includes a variable', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-5 { margin-top: calc(var(--sizing-5) * -1); } @@ -135,7 +135,7 @@ test('a value that includes a calc', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-5 { margin-top: 156px; } @@ -159,7 +159,7 @@ test('a value that includes min/max/clamp functions', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-clamp { margin-top: calc(-1 * clamp(1rem, 100vh, 3rem)); } @@ -193,7 +193,7 @@ test('a keyword value', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .mt-auto { margin-top: auto; } @@ -212,7 +212,7 @@ test('a zero value', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-0, .mt-0 { margin-top: 0; @@ -232,7 +232,7 @@ test('a color', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css``) + return expect(result.css).toMatchFormattedCss(css``) }) }) @@ -242,7 +242,7 @@ test('arbitrary values', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-\[10px\] { margin-top: -10px; } @@ -261,7 +261,7 @@ test('negating a negative scale value', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt-weird { margin-top: 15px; } @@ -280,7 +280,7 @@ test('negating a default value', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt { margin-top: -15px; } @@ -300,7 +300,7 @@ test('using a negative prefix with a negative default scale value', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .-mt { margin-top: -4px; } @@ -323,7 +323,7 @@ test('negating a default value with a configured prefix', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css` + return expect(result.css).toMatchFormattedCss(css` .tw--mt { margin-top: -15px; } @@ -337,6 +337,6 @@ test('arbitrary value keywords should be ignored', () => { } return run('@tailwind utilities', config).then((result) => { - return expect(result.css).toMatchCss(css``) + return expect(result.css).toMatchFormattedCss(css``) }) }) diff --git a/tests/oxide-svelte.test.css b/tests/oxide-svelte.test.css index ef36fec77..d4889d746 100644 --- a/tests/oxide-svelte.test.css +++ b/tests/oxide-svelte.test.css @@ -102,7 +102,7 @@ --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } -@media (min-width: 1024px) { +@media (width >= 1024px) { .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); diff --git a/tests/parseObjectStyles.test.js b/tests/parseObjectStyles.test.js index b823801ee..1771b58b7 100644 --- a/tests/parseObjectStyles.test.js +++ b/tests/parseObjectStyles.test.js @@ -7,7 +7,7 @@ function toCss(nodes) { } test('it parses simple single class definitions', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foobar': { backgroundColor: 'red', color: 'white', @@ -17,15 +17,15 @@ test('it parses simple single class definitions', () => { expect(toCss(result)).toMatchFormattedCss(css` .foobar { - color: #fff; background-color: red; + color: white; padding: 1rem; } `) }) test('it parses multiple class definitions', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', @@ -39,8 +39,8 @@ test('it parses multiple class definitions', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } .bar { @@ -51,7 +51,7 @@ test('it parses multiple class definitions', () => { }) test('it parses nested pseudo-selectors', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', @@ -67,22 +67,22 @@ test('it parses nested pseudo-selectors', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } .foo:hover { background-color: orange; } .foo:focus { - background-color: #00f; + background-color: blue; } `) }) test('it parses top-level media queries', () => { - const result = parseObjectStyles({ - '@media (min-width: 200px)': { + let result = parseObjectStyles({ + '@media (width >= 200px)': { '.foo': { backgroundColor: 'orange', }, @@ -90,7 +90,7 @@ test('it parses top-level media queries', () => { }) expect(toCss(result)).toMatchFormattedCss(css` - @media (min-width: 200px) { + @media (width >= 200px) { .foo { background-color: orange; } @@ -99,12 +99,12 @@ test('it parses top-level media queries', () => { }) test('it parses nested media queries', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', padding: '1rem', - '@media (min-width: 200px)': { + '@media (width >= 200px)': { backgroundColor: 'orange', }, }, @@ -112,11 +112,11 @@ test('it parses nested media queries', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } - @media (min-width: 200px) { + @media (width >= 200px) { .foo { background-color: orange; } @@ -125,7 +125,7 @@ test('it parses nested media queries', () => { }) test('it bubbles nested screen rules', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', @@ -138,8 +138,8 @@ test('it bubbles nested screen rules', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } @screen sm { @@ -151,13 +151,13 @@ test('it bubbles nested screen rules', () => { }) test('it parses pseudo-selectors in nested media queries', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', padding: '1rem', '&:hover': { - '@media (min-width: 200px)': { + '@media (width >= 200px)': { backgroundColor: 'orange', }, }, @@ -166,11 +166,11 @@ test('it parses pseudo-selectors in nested media queries', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } - @media (min-width: 200px) { + @media (width >= 200px) { .foo:hover { background-color: orange; } @@ -179,7 +179,7 @@ test('it parses pseudo-selectors in nested media queries', () => { }) test('it parses descendant selectors', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', @@ -192,8 +192,8 @@ test('it parses descendant selectors', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } .foo .bar { @@ -203,7 +203,7 @@ test('it parses descendant selectors', () => { }) test('it parses nested multi-class selectors', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', @@ -216,8 +216,8 @@ test('it parses nested multi-class selectors', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } .foo.bar { @@ -227,12 +227,12 @@ test('it parses nested multi-class selectors', () => { }) test('it parses nested multi-class selectors in media queries', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { backgroundColor: 'red', color: 'white', padding: '1rem', - '@media (min-width: 200px)': { + '@media (width >= 200px)': { '&.bar': { backgroundColor: 'orange', }, @@ -242,11 +242,11 @@ test('it parses nested multi-class selectors in media queries', () => { expect(toCss(result)).toMatchFormattedCss(css` .foo { - color: #fff; background-color: red; + color: white; padding: 1rem; } - @media (min-width: 200px) { + @media (width >= 200px) { .foo.bar { background-color: orange; } @@ -255,7 +255,7 @@ test('it parses nested multi-class selectors in media queries', () => { }) test('it strips empty selectors when nesting', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ '.foo': { '.bar': { backgroundColor: 'orange', @@ -271,7 +271,7 @@ test('it strips empty selectors when nesting', () => { }) test('it can parse an array of styles', () => { - const result = parseObjectStyles([ + let result = parseObjectStyles([ { '.foo': { backgroundColor: 'orange', @@ -297,13 +297,13 @@ test('it can parse an array of styles', () => { background-color: red; } .foo { - background-color: #00f; + background-color: blue; } `) }) test('custom properties preserve their case', () => { - const result = parseObjectStyles({ + let result = parseObjectStyles({ ':root': { '--colors-aColor-500': '0', }, diff --git a/tests/plugins/divide.test.js b/tests/plugins/divide.test.js index 37bd012ac..a5ffa826f 100644 --- a/tests/plugins/divide.test.js +++ b/tests/plugins/divide.test.js @@ -7,7 +7,7 @@ it('should add the divide styles for divide-y and a default border color', () => } return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` ${defaults} .divide-y > :not([hidden]) ~ :not([hidden]) { @@ -26,7 +26,7 @@ it('should add the divide styles for divide-x and a default border color', () => } return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` ${defaults} .divide-x > :not([hidden]) ~ :not([hidden]) { --tw-divide-x-reverse: 0; @@ -44,7 +44,7 @@ it('should add the divide styles for divide-y-reverse and a default border color } return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` ${defaults} .divide-y-reverse > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 1; @@ -60,7 +60,7 @@ it('should add the divide styles for divide-x-reverse and a default border color } return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` ${defaults} .divide-x-reverse > :not([hidden]) ~ :not([hidden]) { --tw-divide-x-reverse: 1; @@ -76,7 +76,7 @@ it('should only inject the base styles once if we use divide and border at the s } return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` ${defaults} .divide-y > :not([hidden]) ~ :not([hidden]) { --tw-divide-y-reverse: 0; diff --git a/tests/plugins/fontFamily.test.js b/tests/plugins/fontFamily.test.js index f5718909d..c0c7aaceb 100644 --- a/tests/plugins/fontFamily.test.js +++ b/tests/plugins/fontFamily.test.js @@ -108,10 +108,10 @@ test('font-variation-settings can be provided when families are defined as a str } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(` + expect(result.css).toMatchFormattedCss(css` .font-sans { + font-variation-settings: 'opsz' 32; font-family: Inter, sans-serif; - font-variation-settings: "opsz" 32; } `) }) @@ -128,10 +128,10 @@ test('font-variation-settings can be provided when families are defined as an ar } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(` + expect(result.css).toMatchFormattedCss(css` .font-sans { + font-variation-settings: 'opsz' 32; font-family: Inter, sans-serif; - font-variation-settings: "opsz" 32; } `) }) diff --git a/tests/plugins/fontSize.test.js b/tests/plugins/fontSize.test.js index 32214650f..4b0099936 100644 --- a/tests/plugins/fontSize.test.js +++ b/tests/plugins/fontSize.test.js @@ -13,7 +13,7 @@ test('font-size utilities can include a default line-height', () => { } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .text-lg { font-size: 20px; line-height: 28px; @@ -42,7 +42,7 @@ test('font-size utilities can include a default letter-spacing', () => { } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .text-lg { letter-spacing: -0.02em; font-size: 20px; @@ -71,7 +71,7 @@ test('font-size utilities can include a default line-height and letter-spacing', } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .text-lg { letter-spacing: -0.02em; font-size: 20px; @@ -102,7 +102,7 @@ test('font-size utilities can include a font-weight', () => { } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .text-lg { font-size: 20px; font-weight: bold; @@ -147,7 +147,7 @@ test('font-size utilities can include a line-height modifier', () => { } return run('@tailwind utilities', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .text-\[13px\]\/6 { font-size: 13px; line-height: 24px; @@ -168,7 +168,7 @@ test('font-size utilities can include a line-height modifier', () => { font-size: 12px; line-height: 21px; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:text-\[19px\]\/8 { font-size: 19px; line-height: 32px; diff --git a/tests/postcss-plugins/nesting/index.test.js b/tests/postcss-plugins/nesting/index.test.js index fe942a284..d2c339bf8 100644 --- a/tests/postcss-plugins/nesting/index.test.js +++ b/tests/postcss-plugins/nesting/index.test.js @@ -19,7 +19,7 @@ it('should be possible to load a custom nesting plugin', async () => { rule.selector += '-modified' }) }) - ).toMatchCss(css` + ).toMatchFormattedCss(css` .foo-modified { color: black; @media screen(md) { @@ -39,7 +39,7 @@ it('should be possible to load a custom nesting plugin by name (string) instead' } ` - expect(await run(input, 'postcss-nested')).toMatchCss(css` + expect(await run(input, 'postcss-nested')).toMatchFormattedCss(css` .foo { color: black; } @@ -62,7 +62,7 @@ it('should default to the bundled postcss-nested plugin (no options)', async () } ` - expect(await run(input)).toMatchCss(css` + expect(await run(input)).toMatchFormattedCss(css` .foo { color: black; } @@ -85,7 +85,7 @@ it('should default to the bundled postcss-nested plugin (empty options)', async } ` - expect(await run(input, {})).toMatchCss(css` + expect(await run(input, {})).toMatchFormattedCss(css` .foo { color: black; } @@ -108,7 +108,7 @@ it('should be possible to use postcss-nested plugin with options', async () => { } ` - expect(await run(input, postcssNested({ noIsPseudoSelector: true }))).toMatchCss(css` + expect(await run(input, postcssNested({ noIsPseudoSelector: true }))).toMatchFormattedCss(css` .foo { color: black; } @@ -131,7 +131,7 @@ test('@screen rules are replaced with media queries', async () => { } ` - expect(await run(input, postcssNested)).toMatchCss(css` + expect(await run(input, postcssNested)).toMatchFormattedCss(css` .foo { color: black; } @@ -154,7 +154,7 @@ test('@screen rules can work with `@apply`', async () => { } ` - expect(await run(input, postcssNested)).toMatchCss(css` + expect(await run(input, postcssNested)).toMatchFormattedCss(css` .foo { @apply bg-black; } @@ -172,7 +172,7 @@ test('nesting does not break downstream plugin visitors', async () => { .foo { color: black; } - @suppoerts (color: blue) { + @supports (color: blue) { .foo { color: blue; } @@ -186,15 +186,16 @@ test('nesting does not break downstream plugin visitors', async () => { let result = await run(input, plugins) - expect(result).toMatchCss(css` + expect(result).toMatchFormattedCss(css` .foo { - color: #000; + color: black; } - @suppoerts (color: blue) { + @supports (color: blue) { .foo { color: blue; } } + /* Comment */ `) expect(spyPlugin.spies.Once).toHaveBeenCalled() diff --git a/tests/prefix.test.js b/tests/prefix.test.js index c9c0e5f25..1306481e3 100644 --- a/tests/prefix.test.js +++ b/tests/prefix.test.js @@ -94,27 +94,27 @@ test('prefix', () => { .tw-container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .tw-container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .tw-container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .tw-container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .tw-container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .tw-container { max-width: 1536px; } @@ -168,7 +168,7 @@ test('prefix', () => { :is(.tw-dark .dark\:focus\:tw-text-left:focus) { text-align: left; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:tw--ml-5 { margin-left: -1.25rem; } @@ -440,7 +440,7 @@ test('prefix with negative values and variants in the safelist', async () => { .hover\:tw--top-1:hover { top: -0.25rem; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:hover\:-tw-top-1:hover, .sm\:hover\:tw--top-1:hover { top: -0.25rem; diff --git a/tests/raw-content.test.css b/tests/raw-content.test.css index dba9f3194..f93deda00 100644 --- a/tests/raw-content.test.css +++ b/tests/raw-content.test.css @@ -1,37 +1,37 @@ .container { width: 100%; } -@media (min-width: 640px) { +@media (width >= 640px) { .container { max-width: 640px; } } -@media (min-width: 768px) { +@media (width >= 768px) { .container { max-width: 768px; } } -@media (min-width: 1024px) { +@media (width >= 1024px) { .container { max-width: 1024px; } } -@media (min-width: 1280px) { +@media (width >= 1280px) { .container { max-width: 1280px; } } -@media (min-width: 1536px) { +@media (width >= 1536px) { .container { max-width: 1536px; } } .sr-only { - width: 1px; - height: 1px; clip: rect(0, 0, 0, 0); white-space: nowrap; border-width: 0; + width: 1px; + height: 1px; margin: -1px; padding: 0; position: absolute; diff --git a/tests/resolve-defaults-at-rules.test.js b/tests/resolve-defaults-at-rules.test.js index 1d80c780b..0ecb4cdc5 100644 --- a/tests/resolve-defaults-at-rules.test.js +++ b/tests/resolve-defaults-at-rules.test.js @@ -374,7 +374,7 @@ test('with apply', async () => { skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } - @media (min-width: 768px) { + @media (width >= 768px) { .media-queries { --tw-rotate: 45deg; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) @@ -506,7 +506,7 @@ test('with borders', async () => { --tw-border-opacity: 1; border-color: rgb(239 68 68 / var(--tw-border-opacity)); } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:border-2 { border-width: 2px; } @@ -559,7 +559,7 @@ test('with shadows', async () => { .ring-black\/25 { --tw-ring-color: #00000040; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:shadow-xl { --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), diff --git a/tests/responsive-and-variants-atrules.test.js b/tests/responsive-and-variants-atrules.test.js index 4d4a0f507..8eea80729 100644 --- a/tests/responsive-and-variants-atrules.test.js +++ b/tests/responsive-and-variants-atrules.test.js @@ -121,7 +121,7 @@ test('responsive and variants atrules', () => { .both-at-root { color: pink; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:focus\:responsive-in-components:focus { color: #00f; } diff --git a/tests/screenAtRule.test.js b/tests/screenAtRule.test.js index b6f1723c3..af13b5ddf 100644 --- a/tests/screenAtRule.test.js +++ b/tests/screenAtRule.test.js @@ -39,7 +39,7 @@ test('it can generate media queries from configured screen sizes', () => { expect(result.css).toMatchFormattedCss(css` @media (min-width: 500px) { .banana { - color: #ff0; + color: yellow; } } @media (min-width: 750px) { diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index 1a99252f5..88aa59ded 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -43,23 +43,23 @@ test('apply generates source maps', async () => { expect(annotations).toMatchInlineSnapshot(` [ "2:4 -> 1:0", - "2:2-14 -> 2:2-14", - "3:2-13 -> 3:2-13", - "4:2-20 -> 4:2-20", - "5:2-23 -> 5:2-23", - "6:2-57 -> 6:2-57", + "2:2-20 -> 2:2-20", + "3:2-23 -> 3:2-23", + "4:2-57 -> 4:2-57", + "5:2-13 -> 5:2-13", + "6:2-14 -> 6:2-14", "7:0 -> 7:0", "7:4 -> 9:0", - "10:2-14 -> 10:2-14", - "11:2-13 -> 11:2-13", - "12:2-20 -> 12:2-20", - "13:2-57 -> 13:2-57", + "10:2-20 -> 10:2-20", + "11:2-57 -> 11:2-57", + "12:2-13 -> 12:2-13", + "13:2-14 -> 13:2-14", "14:0 -> 14:0", "13:6 -> 16:0", - "17:2-14 -> 17:2-14", - "18:2-13 -> 18:2-13", - "19:2-20 -> 19:2-20", - "20:2-53 -> 20:2-53", + "17:2-20 -> 17:2-20", + "18:2-53 -> 18:2-53", + "19:2-13 -> 19:2-13", + "20:2-14 -> 20:2-14", "21:0 -> 21:0", ] `) @@ -104,9 +104,9 @@ test('preflight + base have source maps', async () => { "21:2-11 -> 21:2-11", "22:0 -> 22:0", "2:4 -> 24:0", - "25:2-11 -> 25:2-11", - "26:2-16 -> 26:2-16", - "27:2-23 -> 27:2-23", + "25:2-16 -> 25:2-16", + "26:2-23 -> 26:2-23", + "27:2-11 -> 27:2-11", "28:0 -> 28:0", "2:4 -> 30:0", "31:2-35 -> 31:2-35", diff --git a/tests/space-utilities.test.js b/tests/space-utilities.test.js index fb027a337..194c63ce2 100644 --- a/tests/space-utilities.test.js +++ b/tests/space-utilities.test.js @@ -10,7 +10,7 @@ test('space-x uses non-logical properties', () => { } return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` ${defaults} .space-x-4 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; @@ -31,7 +31,7 @@ test('space-x uses logical properties', () => { } return run('@tailwind base; @tailwind utilities;', config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` ${defaults} .space-x-4 > :not([hidden]) ~ :not([hidden]) { --tw-space-x-reverse: 0; diff --git a/tests/syntax-svelte.test.js b/tests/syntax-svelte.test.js index 8acd91a5b..d354eee42 100644 --- a/tests/syntax-svelte.test.js +++ b/tests/syntax-svelte.test.js @@ -15,12 +15,12 @@ test('it detects svelte based on the file extension', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .bg-red-500 { --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } - @media (min-width: 1024px) { + @media (width >= 1024px) { .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); @@ -61,12 +61,12 @@ test('using raw with svelte extension', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchCss(css` + expect(result.css).toMatchFormattedCss(css` .bg-red-500 { --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } - @media (min-width: 1024px) { + @media (width >= 1024px) { .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); diff --git a/tests/tailwind-screens.test.js b/tests/tailwind-screens.test.js index 009c02bc3..91eb93c6e 100644 --- a/tests/tailwind-screens.test.js +++ b/tests/tailwind-screens.test.js @@ -19,7 +19,7 @@ test('class variants are inserted at `@tailwind variants`', async () => { .hover\:font-bold:hover { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } @@ -50,7 +50,7 @@ test('`@tailwind screens` works as an alias for `@tailwind variants`', async () .hover\:font-bold:hover { font-weight: 700; } - @media (min-width: 768px) { + @media (width >= 768px) { .md\:font-bold { font-weight: 700; } diff --git a/tests/variant-grouping.test.skip.js b/tests/variant-grouping.test.skip.js index aba113783..156d4a5cf 100644 --- a/tests/variant-grouping.test.skip.js +++ b/tests/variant-grouping.test.skip.js @@ -38,7 +38,7 @@ it('should be possible to group variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 768px) { + @media (width >= 768px) { .md\:\(underline\2c italic\) { font-style: italic; text-decoration-line: underline; @@ -97,7 +97,7 @@ it('should be possible to group multiple variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 768px) { + @media (width >= 768px) { @media (prefers-color-scheme: dark) { .md\:dark\:\(underline\2c italic\) { font-style: italic; @@ -123,7 +123,7 @@ it('should be possible to group nested grouped variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 768px) { + @media (width >= 768px) { .md\:\(underline\2c italic\2c hover\:\(uppercase\2c font-bold\)\) { font-style: italic; text-decoration-line: underline; @@ -155,7 +155,7 @@ it('should be possible to use nested multiple grouped variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 768px) { + @media (width >= 768px) { .md\:\(text-black\2c dark\:\(text-white\2c hover\:focus\:text-gray-100\)\) { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); @@ -195,7 +195,7 @@ it('should be possible to mix and match nesting and different variant combinatio return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-width: 768px) { + @media (width >= 768px) { .md\:\[\&\>\*\]\:\(text-black\2c dark\:\(text-white\2c hover\:\[\@supports\(color\:green\)\]\:\[\&\:nth-child\(2n\=1\)\]\:text-gray-100\)\) diff --git a/tests/variants.test.css b/tests/variants.test.css index 2bb486303..57291001a 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -73,7 +73,7 @@ .first\:flex:first-child, .last\:flex:last-child, .only\:flex:only-child, -.odd\:flex:nth-child(2n + 1), +.odd\:flex:nth-child(odd), .even\:flex:nth-child(2n), .first-of-type\:flex:first-of-type, .last-of-type\:flex:last-of-type, @@ -84,8 +84,15 @@ .default\:flex:default, .checked\:flex:checked, .indeterminate\:flex:indeterminate, -.placeholder-shown\:flex:placeholder-shown, -.autofill\:flex:autofill, +.placeholder-shown\:flex:placeholder-shown { + display: flex; +} +.autofill\:flex:-webkit-autofill { + display: flex; +} +.autofill\:flex:autofill { + display: flex; +} .optional\:flex:optional, .required\:flex:required, .valid\:flex:valid, @@ -111,7 +118,88 @@ .group:first-child .group-first\:flex, .group:last-child .group-last\:flex, .group:only-child .group-only\:flex, -.group:nth-child(2n + 1) .group-odd\:flex, +.group:nth-child(odd) .group-odd\:flex, +.group:nth-child(2n) .group-even\:flex, +.group:first-of-type .group-first-of-type\:flex, +.group:last-of-type .group-last-of-type\:flex, +.group:only-of-type .group-only-of-type\:flex, +.group:visited .group-visited\:flex, +.group:target .group-target\:flex, +.group[open] .group-open\:flex, +.group:default .group-default\:flex, +.group:checked .group-checked\:flex, +.group:indeterminate .group-indeterminate\:flex, +.group:placeholder-shown .group-placeholder-shown\:flex, +.group:-webkit-autofill .group-autofill\:flex, +.group:optional .group-optional\:flex, +.group:required .group-required\:flex, +.group:valid .group-valid\:flex, +.group:invalid .group-invalid\:flex, +.group:in-range .group-in-range\:flex, +.group:out-of-range .group-out-of-range\:flex, +.group:read-only .group-read-only\:flex, +.group:empty .group-empty\:flex, +.group:focus-within .group-focus-within\:flex, +.group:hover .group-hover\:flex, +.group[open]:hover .group-open\:group-hover\:flex, +.group:focus .group-focus\:flex, +.group[open]:focus .group-open\:group-focus\:flex, +.group:focus:hover .group-focus\:group-hover\:flex, +.group:focus-visible .group-focus-visible\:flex, +.group:active .group-active\:flex, +.group:enabled .group-enabled\:flex, +.group:disabled .group-disabled\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:flex, +.group:disabled:focus:hover .group-disabled\:group-focus\:group-hover\:first\:flex:first-child, +.peer:first-child ~ .peer-first\:flex, +.peer:last-child ~ .peer-last\:flex, +.peer:only-child ~ .peer-only\:flex, +.peer:nth-child(odd) ~ .peer-odd\:flex, +.peer:nth-child(2n) ~ .peer-even\:flex, +.peer:first-of-type ~ .peer-first-of-type\:flex, +.peer:last-of-type ~ .peer-last-of-type\:flex, +.peer:only-of-type ~ .peer-only-of-type\:flex, +.peer:visited ~ .peer-visited\:flex, +.peer:target ~ .peer-target\:flex, +.peer[open] ~ .peer-open\:flex, +.peer:default ~ .peer-default\:flex, +.peer:checked ~ .peer-checked\:flex, +.peer:indeterminate ~ .peer-indeterminate\:flex, +.peer:placeholder-shown ~ .peer-placeholder-shown\:flex, +.peer:-webkit-autofill ~ .peer-autofill\:flex, +.peer:optional ~ .peer-optional\:flex, +.peer:required ~ .peer-required\:flex, +.peer:valid ~ .peer-valid\:flex, +.peer:invalid ~ .peer-invalid\:flex, +.peer:in-range ~ .peer-in-range\:flex, +.peer:out-of-range ~ .peer-out-of-range\:flex, +.peer:read-only ~ .peer-read-only\:flex, +.peer:empty ~ .peer-empty\:flex, +.peer:focus-within ~ .peer-focus-within\:flex, +.peer:hover ~ .peer-hover\:flex, +.peer:focus ~ .peer-focus\:flex, +.peer:focus:hover ~ .peer-focus\:peer-hover\:flex, +.peer:focus-visible ~ .peer-focus-visible\:flex, +.peer:active ~ .peer-active\:flex, +.peer:enabled ~ .peer-enabled\:flex, +.peer:disabled ~ .peer-disabled\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:flex, +.peer:disabled:focus:hover ~ .peer-disabled\:peer-focus\:peer-hover\:first\:flex:first-child, +:-webkit-any([dir='ltr'] .ltr\:flex), +:-webkit-any([dir='rtl'] .rtl\:flex) { + display: flex; +} +.open\:hover\:flex:hover[open], +.focus\:flex:focus, +.focus\:hover\:flex:hover:focus, +.focus-visible\:flex:focus-visible, +.active\:flex:active, +.enabled\:flex:enabled, +.disabled\:flex:disabled, +.group:first-child .group-first\:flex, +.group:last-child .group-last\:flex, +.group:only-child .group-only\:flex, +.group:nth-child(odd) .group-odd\:flex, .group:nth-child(2n) .group-even\:flex, .group:first-of-type .group-first-of-type\:flex, .group:last-of-type .group-last-of-type\:flex, @@ -147,7 +235,7 @@ .peer:first-child ~ .peer-first\:flex, .peer:last-child ~ .peer-last\:flex, .peer:only-child ~ .peer-only\:flex, -.peer:nth-child(2n + 1) ~ .peer-odd\:flex, +.peer:nth-child(odd) ~ .peer-odd\:flex, .peer:nth-child(2n) ~ .peer-even\:flex, .peer:first-of-type ~ .peer-first-of-type\:flex, .peer:last-of-type ~ .peer-last-of-type\:flex, @@ -212,31 +300,31 @@ display: flex; } } -@media (min-width: 640px) { +@media (width >= 640px) { .sm\:flex, .sm\:active\:flex:active { display: flex; } } -@media (min-width: 768px) { +@media (width >= 768px) { .md\:flex, .group:focus .md\:group-focus\:flex { display: flex; } } -@media (min-width: 1024px) { +@media (width >= 1024px) { .lg\:flex, :is(.dark .lg\:dark\:flex) { display: flex; } } -@media (min-width: 1280px) { +@media (width >= 1280px) { .xl\:flex, :is(.dark .xl\:dark\:disabled\:flex:disabled) { display: flex; } } -@media (min-width: 1536px) { +@media (width >= 1536px) { .\32 xl\:flex { display: flex; } diff --git a/tests/variants.test.js b/tests/variants.test.js index f948e1b2f..1e88aa4e1 100644 --- a/tests/variants.test.js +++ b/tests/variants.test.js @@ -28,8 +28,8 @@ test('order matters and produces different behaviour', () => { content: [ { raw: html` -
-
+
+
`, }, ], @@ -37,11 +37,11 @@ test('order matters and produces different behaviour', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - .file\:hover\:flex:hover::file-selector-button { - display: flex; + .file\:hover\:\[--value\:2\]:hover::file-selector-button { + --value: 2; } - .hover\:file\:flex::file-selector-button:hover { - display: flex; + .hover\:file\:\[--value\:1\]::file-selector-button:hover { + --value: 1; } `) }) @@ -318,7 +318,7 @@ test('custom addVariant with more complex media query params', () => { return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media screen and (max-width: 600px) { + @media screen and (width <= 600px) { .magic\:text-center { text-align: center; } @@ -491,7 +491,7 @@ it('should be possible to use responsive modifiers that are defined with special return run('@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (max-width: 399px) { + @media (width <= 399px) { .\ { return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:underline { text-decoration-line: underline; } @@ -538,31 +538,31 @@ it('variants for utilities should not be produced in a file without a utilities return run('@tailwind components', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:container { width: 100%; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:container { max-width: 640px; } } - @media (min-width: 768px) { + @media (width >= 768px) { .sm\:container { max-width: 768px; } } - @media (min-width: 1024px) { + @media (width >= 1024px) { .sm\:container { max-width: 1024px; } } - @media (min-width: 1280px) { + @media (width >= 1280px) { .sm\:container { max-width: 1280px; } } - @media (min-width: 1536px) { + @media (width >= 1536px) { .sm\:container { max-width: 1536px; } @@ -622,7 +622,7 @@ it('appends variants to the correct place when using postcss documents', () => { .underline { text-decoration-line: underline; } - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:underline { text-decoration-line: underline; } @@ -654,7 +654,7 @@ it('variants support multiple, grouped selectors (html)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:base1 .foo, .sm\:base1 .bar, .sm\:base2 .bar .base2-foo { @@ -687,7 +687,7 @@ it('variants support multiple, grouped selectors (apply)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { + @media (width >= 640px) { .baz .foo, .baz .bar { color: red; @@ -716,7 +716,7 @@ it('variants only picks the used selectors in a group (html)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { + @media (width >= 640px) { .sm\:b { color: red; } @@ -747,7 +747,7 @@ it('variants only picks the used selectors in a group (apply)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (min-width: 640px) { + @media (width >= 640px) { .baz { color: red; } @@ -915,7 +915,7 @@ test('class inside pseudo-class function :has', () => { html:has(.hover\:foo:hover) { color: green; } - @media (min-width: 640px) { + @media (width >= 640px) { :where(.sm\:foo) { color: red; } @@ -995,7 +995,7 @@ test('variants with slashes in them work', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) { + @media (aspect-ratio >= 1 / 10) { .ar-1\/10\:flex { display: flex; } @@ -1031,7 +1031,7 @@ test('variants with slashes support modifiers', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (min-aspect-ratio: 1 / 10) and (foo: 20) { + @media (aspect-ratio >= 1 / 10) and (foo: 20) { .ar-1\/10\/20\:flex { display: flex; } From 55daf8e0f55348788af18ca590e86aabd51e5d9b Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 7 Jun 2023 17:44:35 +0200 Subject: [PATCH 52/85] Ensure the oxide parser has feature parity with the stable RegEx parser (#11389) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * WIP * use `parse` instead of `defaultExtractor` * skip `Vue` describe block * add a few more dedicated arbitrary values/properties tests * use parallel parsing * splitup Vue tests * add some Rust specific tests * setup parse candidate strings test system These tests will run against the `Regex` and `Rust` based parsers. We have groups of classes of various shapes and forms + variants and rendered in various template situation (plain, html, Vue, ...) + enable all skipped tests * ensure we also validate the classes with variants The classes with variants are built in the `templateTable` function, so we get them out again by using the potional arguments of the `test.each` cb function. * cleanup test suite * add "anti-test" tests To make sure that we are _not_ parsing out certain values given a certain input. * Add ParseAction enum * Restart parsing following an arbitrary parse failure * Split variants off before validating the uility part * Collapse candidate from the end when validation fails * Support `<`, and `>` in variant position * fix error * format parser.rs * Refactor * Update editorconfig * wip * wip * Refactor * Refactor * Simplify * wip * wip * wip * wip * wip * wip * wip * run `cargo clippy --fix` * run `cargo fmt` * implement `cargo clippy` suggestions These were not applied using `cargo clippy --fix` * only allow `.` in the candidate part when surrounded by 0-9 This is only in the candidate part, not the arbitrary part. * % characters can only appear at the end after digits * > and < should only be part of variants (start OR end) It can technically be inside the candidate when we have stacked variants: ``` dark::underline ``` * handle parsing utilities within quotes, parans or brackets * mark `pt-1.5` as an expected value sliced out from `["pt-1.5"]` * Add cursor abstraction * wip * disable the oxideParser if using a custom `prefix` or `separator` * update tests * Use cursor abstraction * Refactor more code toward use of global cursor * wip * simplify * Simplify * Simplify * Simplify * Cleanup * wip * Simplify * wip * Simplify * Handle candidates ending with % sign * Tweak code a bit * fmt * Simplify * Add cursor details to trace * cargo fmt * use preferred `zoom-0.5` name instead of `zoom-.5` * drop over-extracted utilities in oxide parser The RegEx parser does extract `underline` from ```html
``` ... but that's not needed and is not happening in the oxide parser This means that we have to make the output check a little bit different but they are explicit based on the feature flag. * allow extracting variants+utilities inside `{}` for the oxide parser * characters in candidates such as `group-${id}` should not be allowed * do not extract any of the following candidate `w-[foo-bar]w-[bar-baz]` * ensure we can consume the full candidate and discard it * Add fast skipping of whitespace * Use fast skipping whenever possible * Add fast skipping to benchmark * Hand-tune to generate more optimized assembly * Move code around a bit This makes sure all the fancy SIMD stuff is as early as possible. This results in an extremely minor perf increase. * Undo tweak no meaningful perf difference in real world scenarios * Disable fast skipping for now It needs to be done in a different spot so it doesn’t affect how things are returned * Change test names * Fix normalize config error * cleanup a bit * Cleanup * Extract validation result enum * Cleanup comments * Simplify * Fix formatting * Run clippy * wip * add `md>` under the special characters test set --------- Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Co-authored-by: Jordan Pittman --- .editorconfig | 8 + oxide/crates/core/benches/parse_candidates.rs | 12 + oxide/crates/core/src/cursor.rs | 159 ++++ oxide/crates/core/src/fast_skip.rs | 89 +++ oxide/crates/core/src/lib.rs | 2 + oxide/crates/core/src/parser.rs | 711 ++++++++++++++---- src/featureFlags.js | 2 +- src/util/normalizeConfig.js | 17 +- tests/animations.test.js | 15 +- tests/arbitrary-variants.test.js | 113 ++- tests/basic-usage.test.js | 55 +- tests/parse-candidate-strings.test.js | 423 +++++++++++ 12 files changed, 1384 insertions(+), 222 deletions(-) create mode 100644 oxide/crates/core/src/cursor.rs create mode 100644 oxide/crates/core/src/fast_skip.rs create mode 100644 tests/parse-candidate-strings.test.js diff --git a/.editorconfig b/.editorconfig index c6c8b3621..f6d83b7c7 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,3 +7,11 @@ end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true + +[*.rs] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/oxide/crates/core/benches/parse_candidates.rs b/oxide/crates/core/benches/parse_candidates.rs index 55c919471..aacc1469e 100644 --- a/oxide/crates/core/benches/parse_candidates.rs +++ b/oxide/crates/core/benches/parse_candidates.rs @@ -31,6 +31,18 @@ pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("parse_candidate_strings (real world)", |b| { b.iter(|| parse(include_bytes!("./fixtures/template-499.html"))) }); + + let mut group = c.benchmark_group("sample-size-example"); + group.sample_size(10); + + group.bench_function("parse_candidate_strings (fast space skipping)", |b| { + let count = 10_000; + let crazy1 = format!("{}underline", " ".repeat(count)); + let crazy2 = crazy1.repeat(count); + let crazy3 = crazy2.as_bytes(); + + b.iter(|| parse(black_box(crazy3))) + }); } criterion_group!(benches, criterion_benchmark); diff --git a/oxide/crates/core/src/cursor.rs b/oxide/crates/core/src/cursor.rs new file mode 100644 index 000000000..0c422c6ff --- /dev/null +++ b/oxide/crates/core/src/cursor.rs @@ -0,0 +1,159 @@ +use std::{ascii::escape_default, fmt::Display}; + +#[derive(Debug, Clone)] +pub struct Cursor<'a> { + // The input we're scanning + pub input: &'a [u8], + + // The location of the cursor in the input + pub pos: usize, + + /// Is the cursor at the start of the input + pub at_start: bool, + + /// Is the cursor at the end of the input + pub at_end: bool, + + /// The previously consumed character + /// If `at_start` is true, this will be NUL + pub prev: u8, + + /// The current character + pub curr: u8, + + /// The upcoming character (if any) + /// If `at_end` is true, this will be NUL + pub next: u8, +} + +impl<'a> Cursor<'a> { + pub fn new(input: &'a [u8]) -> Self { + let mut cursor = Self { + input, + pos: 0, + at_start: true, + at_end: false, + prev: 0x00, + curr: 0x00, + next: 0x00, + }; + cursor.move_to(0); + cursor + } + + pub fn rewind_by(&mut self, amount: usize) { + self.move_to(self.pos.saturating_sub(amount)); + } + + pub fn advance_by(&mut self, amount: usize) { + self.move_to(self.pos.saturating_add(amount)); + } + + pub fn move_to(&mut self, pos: usize) { + let len = self.input.len(); + let pos = pos.clamp(0, len); + + self.pos = pos; + self.at_start = pos == 0; + self.at_end = pos + 1 >= len; + + self.prev = if pos > 0 { self.input[pos - 1] } else { 0x00 }; + self.curr = if pos < len { self.input[pos] } else { 0x00 }; + self.next = if pos + 1 < len { + self.input[pos + 1] + } else { + 0x00 + }; + } +} + +impl<'a> Display for Cursor<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let len = self.input.len().to_string(); + + let pos = format!("{: >len_count$}", self.pos, len_count = len.len()); + write!(f, "{}/{} ", pos, len)?; + + if self.at_start { + write!(f, "S ")?; + } else if self.at_end { + write!(f, "E ")?; + } else { + write!(f, "M ")?; + } + + fn to_str(c: u8) -> String { + if c == 0x00 { + "NUL".into() + } else { + format!("{:?}", escape_default(c).to_string()) + } + } + + write!( + f, + "[{} {} {}]", + to_str(self.prev), + to_str(self.curr), + to_str(self.next) + ) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_cursor() { + let mut cursor = Cursor::new(b"hello world"); + assert_eq!(cursor.pos, 0); + assert!(cursor.at_start); + assert!(!cursor.at_end); + assert_eq!(cursor.prev, 0x00); + assert_eq!(cursor.curr, b'h'); + assert_eq!(cursor.next, b'e'); + + cursor.advance_by(1); + assert_eq!(cursor.pos, 1); + assert!(!cursor.at_start); + assert!(!cursor.at_end); + assert_eq!(cursor.prev, b'h'); + assert_eq!(cursor.curr, b'e'); + assert_eq!(cursor.next, b'l'); + + // Advancing too far should stop at the end + cursor.advance_by(10); + assert_eq!(cursor.pos, 11); + assert!(!cursor.at_start); + assert!(cursor.at_end); + assert_eq!(cursor.prev, b'd'); + assert_eq!(cursor.curr, 0x00); + assert_eq!(cursor.next, 0x00); + + // Can't advance past the end + cursor.advance_by(1); + assert_eq!(cursor.pos, 11); + assert!(!cursor.at_start); + assert!(cursor.at_end); + assert_eq!(cursor.prev, b'd'); + assert_eq!(cursor.curr, 0x00); + assert_eq!(cursor.next, 0x00); + + cursor.rewind_by(1); + assert_eq!(cursor.pos, 10); + assert!(!cursor.at_start); + assert!(cursor.at_end); + assert_eq!(cursor.prev, b'l'); + assert_eq!(cursor.curr, b'd'); + assert_eq!(cursor.next, 0x00); + + cursor.rewind_by(10); + assert_eq!(cursor.pos, 0); + assert!(cursor.at_start); + assert!(!cursor.at_end); + assert_eq!(cursor.prev, 0x00); + assert_eq!(cursor.curr, b'h'); + assert_eq!(cursor.next, b'e'); + } +} diff --git a/oxide/crates/core/src/fast_skip.rs b/oxide/crates/core/src/fast_skip.rs new file mode 100644 index 000000000..488e61bd6 --- /dev/null +++ b/oxide/crates/core/src/fast_skip.rs @@ -0,0 +1,89 @@ +use crate::cursor::Cursor; + +const STRIDE: usize = 16; +type Mask = [bool; STRIDE]; + +#[inline(always)] +pub fn fast_skip(cursor: &Cursor) -> Option { + // If we don't have enough bytes left to check then bail early + if cursor.pos + STRIDE >= cursor.input.len() { + return None; + } + + if !cursor.curr.is_ascii_whitespace() { + return None; + } + + let mut offset = 1; + + // SAFETY: We've already checked (indirectly) that this index is valid + let remaining = unsafe { cursor.input.get_unchecked(cursor.pos..) }; + + // NOTE: This loop uses primitives designed to be auto-vectorized + // Do not change this loop without benchmarking the results + // And checking the generated assembly using godbolt.org + for (i, chunk) in remaining.chunks_exact(STRIDE).enumerate() { + let value = load(chunk); + let is_whitespace = is_ascii_whitespace(value); + let is_all_whitespace = all_true(is_whitespace); + + if is_all_whitespace { + offset = (i + 1) * STRIDE; + } else { + break; + } + } + + Some(cursor.pos + offset) +} + +#[inline(always)] +fn load(input: &[u8]) -> [u8; STRIDE] { + let mut value = [0u8; STRIDE]; + value.copy_from_slice(input); + value +} + +#[inline(always)] +fn eq(input: [u8; STRIDE], val: u8) -> Mask { + let mut res = [false; STRIDE]; + for n in 0..STRIDE { + res[n] = input[n] == val + } + res +} + +#[inline(always)] +fn or(a: [bool; STRIDE], b: [bool; STRIDE]) -> [bool; STRIDE] { + let mut res = [false; STRIDE]; + for n in 0..STRIDE { + res[n] = a[n] | b[n]; + } + res +} + +#[inline(always)] +fn all_true(a: [bool; STRIDE]) -> bool { + let mut res = true; + for item in a.iter().take(STRIDE) { + res &= item; + } + res +} + +#[inline(always)] +fn is_ascii_whitespace(value: [u8; STRIDE]) -> [bool; STRIDE] { + let whitespace_1 = eq(value, b'\t'); + let whitespace_2 = eq(value, b'\n'); + let whitespace_3 = eq(value, b'\x0C'); + let whitespace_4 = eq(value, b'\r'); + let whitespace_5 = eq(value, b' '); + + or( + or( + or(or(whitespace_1, whitespace_2), whitespace_3), + whitespace_4, + ), + whitespace_5, + ) +} diff --git a/oxide/crates/core/src/lib.rs b/oxide/crates/core/src/lib.rs index 858e17a2d..9596c6855 100644 --- a/oxide/crates/core/src/lib.rs +++ b/oxide/crates/core/src/lib.rs @@ -9,6 +9,8 @@ use tracing::event; use walkdir::WalkDir; pub mod candidate; +pub mod cursor; +pub mod fast_skip; pub mod glob; pub mod location; pub mod modifier; diff --git a/oxide/crates/core/src/parser.rs b/oxide/crates/core/src/parser.rs index acee57022..92740847b 100644 --- a/oxide/crates/core/src/parser.rs +++ b/oxide/crates/core/src/parser.rs @@ -2,6 +2,39 @@ use bstr::ByteSlice; use fxhash::FxHashSet; use tracing::trace; +use crate::{cursor::Cursor, fast_skip::fast_skip}; + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum ParseAction<'a> { + Consume, + Skip, + RestartAt(usize), + + SingleCandidate(&'a [u8]), + MultipleCandidates(Vec<&'a [u8]>), + Done, +} + +#[derive(Debug, PartialEq, Eq, Clone)] +pub enum Bracketing<'a> { + Included(&'a [u8]), + Wrapped(&'a [u8]), + None, +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub struct SplitCandidate<'a> { + variant: &'a [u8], + utility: &'a [u8], +} + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +pub enum ValidationResult { + Invalid, + Valid, + Restart, +} + #[derive(Default)] pub struct ExtractorOptions { pub preserve_spaces_in_arbitrary: bool, @@ -11,9 +44,7 @@ pub struct Extractor<'a> { opts: ExtractorOptions, input: &'a [u8], - pos: usize, - - prev: u8, + cursor: Cursor<'a>, idx_start: usize, idx_end: usize, @@ -24,24 +55,24 @@ pub struct Extractor<'a> { in_candidate: bool, in_escape: bool, + discard_next: bool, + quote_stack: Vec, bracket_stack: Vec, - // buffer: [Option<&'a [u8]>; 8], } impl<'a> Extractor<'a> { pub fn all(input: &'a [u8], opts: ExtractorOptions) -> Vec<&'a [u8]> { - Self::new(input, opts).collect() + Self::new(input, opts).flatten().collect() } pub fn unique(input: &'a [u8], opts: ExtractorOptions) -> FxHashSet<&'a [u8]> { let mut candidates: FxHashSet<&[u8]> = Default::default(); candidates.reserve(100); - candidates.extend(Self::new(input, opts)); + candidates.extend(Self::new(input, opts).flatten()); candidates } - #[cfg(test)] pub fn unique_ord(input: &'a [u8], opts: ExtractorOptions) -> Vec<&'a [u8]> { // This is an inefficient way to get an ordered, unique // list as a Vec but it is only meant for testing. @@ -59,8 +90,7 @@ impl<'a> Extractor<'a> { Self { opts, input, - pos: 0, - prev: 0, + cursor: Cursor::new(input), idx_start: 0, idx_end: 0, @@ -70,10 +100,11 @@ impl<'a> Extractor<'a> { in_candidate: false, in_escape: false, + discard_next: false, + idx_last: input.len(), quote_stack: Vec::with_capacity(8), bracket_stack: Vec::with_capacity(8), - // buffer: [None; 8], } } } @@ -86,126 +117,212 @@ impl<'a> Extractor<'a> { } #[inline(always)] - fn get_current_candidate(&mut self) -> Option<&'a [u8]> { - let candidate = &self.input[self.idx_start..=self.idx_end]; + fn get_current_candidate(&mut self) -> ParseAction<'a> { + if self.discard_next { + return ParseAction::Skip; + } - if Extractor::is_valid_candidate_string(candidate) { - Some(candidate) - } else { - None + let mut candidate = &self.input[self.idx_start..=self.idx_end]; + + while !candidate.is_empty() { + match Extractor::is_valid_candidate_string(candidate) { + ValidationResult::Valid => return ParseAction::SingleCandidate(candidate), + ValidationResult::Restart => return ParseAction::RestartAt(self.idx_start + 1), + _ => {} + } + + match candidate.split_last() { + // At this point the candidate is technically invalid, however it can be that it + // has a few dangling characters attached to it. For example, think about a + // JavaScript object: + // + // ```js + // { underline: true } + // ``` + // + // The candidate at this point will be `underline:`, which is invalid. However, we + // can assume in this case that the `:` should not be there, and therefore we can + // try to slice it off and retry the validation. + Some((b':' | b'/' | b'.', head)) => { + candidate = head; + } + + // It could also be that we have the candidate is nested inside of bracket or quote + // pairs. In this case we want to retrieve the inner part and try to validate that + // inner part instead. For example, in a JavaScript array: + // + // ```js + // let myClasses = ["underline"] + // ``` + // + // The `underline` is nested inside of quotes and in square brackets. Let's try to + // get the inner part and validate that instead. + _ => match Self::slice_surrounding(candidate) { + Some(shorter) if shorter != candidate => { + candidate = shorter; + } + _ => break, + }, + } + } + + ParseAction::Consume + } + + #[inline(always)] + fn split_candidate(candidate: &'a [u8]) -> SplitCandidate { + let mut brackets = 0; + let mut idx_end = 0; + + for (n, c) in candidate.iter().enumerate() { + match c { + b'[' => brackets += 1, + b']' if brackets > 0 => brackets -= 1, + b':' if brackets == 0 => idx_end = n + 1, + _ => {} + } + } + + SplitCandidate { + variant: &candidate[0..idx_end], + utility: &candidate[idx_end..], } } #[inline(always)] - fn is_valid_candidate_string(candidate: &'a [u8]) -> bool { - let original_candidate = &candidate; - let mut offset = 0; + fn contains_in_constrained(candidate: &'a [u8], bytes: Vec) -> bool { + let mut brackets = 0; - // Some special cases that we can ignore while testing the validations. - if candidate.starts_with(b"!-") { + for c in candidate { + match c { + b'[' => brackets += 1, + b']' if brackets > 0 => brackets -= 1, + _ if brackets == 0 && bytes.contains(c) => return true, + _ => {} + } + } + + false + } + + #[inline(always)] + fn is_valid_candidate_string(candidate: &'a [u8]) -> ValidationResult { + let split_candidate = Extractor::split_candidate(candidate); + + let mut offset = 0; + let utility = &split_candidate.utility; + let original_utility = &utility; + + // Some special cases that we can ignore while validating + if utility.starts_with(b"!-") { offset += 2; - } else if candidate.starts_with(b"!") || candidate.starts_with(b"-") { + } else if utility.starts_with(b"!") || utility.starts_with(b"-") { offset += 1; } + // These are allowed in arbitrary values and in variants but nowhere else + if Extractor::contains_in_constrained(utility, vec![b'<', b'>']) { + return ValidationResult::Restart; + } + // Pluck out the part that we are interested in. - let candidate = &candidate[offset..]; + let utility = &utility[offset..]; // Validations // We should have _something_ - if candidate.is_empty() { - return false; + if utility.is_empty() { + return ValidationResult::Invalid; } // = b'0' && candidate[0] <= b'9' && !candidate.contains(&b':') { - return false; + if utility[0] >= b'0' && utility[0] <= b'9' && !utility.contains(&b':') { + return ValidationResult::Invalid; } // In case of an arbitrary property, we should have at least this structure: [a:b] - if candidate.starts_with(b"[") && candidate.ends_with(b"]") { + if utility.starts_with(b"[") && utility.ends_with(b"]") { // [a:b] is at least 5 characters long - if candidate.len() < 5 { - return false; + if utility.len() < 5 { + return ValidationResult::Invalid; } // Should contain a `:` - if !candidate.contains(&b':') { - return false; + if !utility.contains(&b':') { + return ValidationResult::Invalid; } // Now that we validated that the candidate is technically fine, let's ensure that it // doesn't start with a `-` because that would make it invalid for arbitrary properties. - if original_candidate.starts_with(b"-") || original_candidate.starts_with(b"!-") { - return false; + if original_utility.starts_with(b"-") || original_utility.starts_with(b"!-") { + return ValidationResult::Invalid; } // The ':` must be preceded by a-Z0-9 because it represents a property name. - let colon = candidate.find(":").unwrap(); + let colon = utility.find(":").unwrap(); - if !candidate + if !utility .chars() .nth(colon - 1) .map_or_else(|| false, |c| c.is_ascii_alphanumeric()) { - return false; + return ValidationResult::Invalid; } } // In case of an arbitrary property, we should not have a modifier of any kind - if candidate.starts_with(b"[") { + if utility.starts_with(b"[") { if let Some(first_non_escaped_closing_bracket_idx) = - candidate.char_indices().position(|(s, _, other)| { + utility.char_indices().position(|(s, _, other)| { other == ']' - && candidate + && utility .get((s - 1)..s) .map(|c| !c.eq(b"\\")) .unwrap_or(false) }) { - if let Some(next) = candidate + if let Some(next) = utility .chars() .nth(first_non_escaped_closing_bracket_idx + 1) { // `/` is the indicator for a modifier, this is not allowed after arbitrary // properties if next == '/' { - return false; + return ValidationResult::Invalid; } } } } - true + ValidationResult::Valid } #[inline(always)] - fn parse_escaped(&mut self) -> bool { + fn parse_escaped(&mut self) -> ParseAction<'a> { // If this character is escaped, we don't care about it. // It gets consumed. trace!("Escape::Consume"); self.in_escape = false; - true + ParseAction::Consume } #[inline(always)] - fn parse_arbitrary(&mut self, curr: u8, pos: usize) -> bool { + fn parse_arbitrary(&mut self) -> ParseAction<'a> { // In this we could technically use memchr 6 times (then looped) to find the indexes / bounds of arbitrary valuesq if self.in_escape { return self.parse_escaped(); } - match curr { + match self.cursor.curr { b'\\' => { // The `\` character is used to escape characters in arbitrary content _and_ to prevent the starting of arbitrary content trace!("Arbitrary::Escape"); @@ -213,7 +330,7 @@ impl<'a> Extractor<'a> { } // Make sure the brackets are balanced - b'[' => self.bracket_stack.push(curr), + b'[' => self.bracket_stack.push(self.cursor.curr), b']' => match self.bracket_stack.last() { // We've ended a nested bracket Some(&last_bracket) if last_bracket == b'[' => { @@ -222,12 +339,16 @@ impl<'a> Extractor<'a> { // This is the last bracket meaning the end of arbitrary content _ if !self.in_quotes() => { + if matches!(self.cursor.next, b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9') { + return ParseAction::Consume; + } + trace!("Arbitrary::End\t"); self.in_arbitrary = false; - if pos - self.idx_arbitrary_start == 1 { + if self.cursor.pos - self.idx_arbitrary_start == 1 { // We have an empty arbitrary value, which is not allowed - return false; + return ParseAction::Skip; } } @@ -239,19 +360,22 @@ impl<'a> Extractor<'a> { // These can "escape" the arbitrary value mode // switching of `[` and `]` characters b'"' | b'\'' | b'`' => match self.quote_stack.last() { - Some(&last_quote) if last_quote == curr => { + Some(&last_quote) if last_quote == self.cursor.curr => { trace!("Quote::End\t"); self.quote_stack.pop(); } _ => { trace!("Quote::Start\t"); - self.quote_stack.push(curr); + self.quote_stack.push(self.cursor.curr); } }, b' ' if !self.opts.preserve_spaces_in_arbitrary => { trace!("Arbitrary::SkipAndEndEarly\t"); - return false; + + // Restart the parser ahead of the arbitrary value + // It may pick up more candidates + return ParseAction::RestartAt(self.idx_arbitrary_start + 1); } // Arbitrary values allow any character inside them @@ -262,51 +386,55 @@ impl<'a> Extractor<'a> { } } - true + ParseAction::Consume } #[inline(always)] - fn parse_start(&mut self, curr: u8, pos: usize) -> bool { - match curr { + fn parse_start(&mut self) -> ParseAction<'a> { + match self.cursor.curr { // Enter arbitrary value mode b'[' => { trace!("Arbitrary::Start\t"); self.in_arbitrary = true; - self.idx_arbitrary_start = pos; + self.idx_arbitrary_start = self.cursor.pos; - true + ParseAction::Consume } // Allowed first characters. - b'@' | b'!' | b'-' | b'<' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => { + b'@' | b'!' | b'-' | b'<' | b'>' | b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => { // TODO: A bunch of characters that we currently support but maybe we only want it behind // a flag. E.g.: '' | '$' | '^' | '_' + // | '$' | '^' | '_' + + // When the new candidate is preceeded by a `:`, then we want to keep parsing, but + // throw away the full candidate because it can not be a valid candidate at the end + // of the day. + if self.cursor.prev == b':' { + self.discard_next = true; + } trace!("Candidate::Start\t"); - true + ParseAction::Consume } - _ => false, + _ => ParseAction::Skip, } } #[inline(always)] - fn parse_continue(&mut self, prev: u8, curr: u8, pos: usize) -> bool { - match curr { + fn parse_continue(&mut self) -> ParseAction<'a> { + match self.cursor.curr { // Enter arbitrary value mode - b'[' if prev == b'@' - || prev == b'-' - || prev == b' ' - || prev == b':' // Variant separator - || prev == b'/' // Modifier separator - || prev == b'!' - || prev == b'\0' => + b'[' if matches!( + self.cursor.prev, + b'@' | b'-' | b' ' | b':' | b'/' | b'!' | b'\0' + ) => { trace!("Arbitrary::Start\t"); self.in_arbitrary = true; - self.idx_arbitrary_start = pos; + self.idx_arbitrary_start = self.cursor.pos; } // Can't enter arbitrary value mode @@ -314,154 +442,305 @@ impl<'a> Extractor<'a> { b'[' => { trace!("Arbitrary::Skip_Start\t"); - return false; + return ParseAction::Skip; + } + + // A % can only appear at the end of the candidate itself. It can also only be after a + // digit 0-9. This covers the following cases: + // - from-15% + b'%' if self.cursor.prev.is_ascii_digit() => { + return match (self.cursor.at_end, self.cursor.next) { + // End of string == end of candidate == okay + (true, _) => ParseAction::Consume, + + // Looks like the end of a candidate == okay + (_, b' ' | b'\'' | b'"' | b'`') => ParseAction::Consume, + + // Otherwise, not a valid character in a candidate + _ => ParseAction::Skip, + }; + } + b'%' => return ParseAction::Skip, + + // < and > can only be part of a variant and only be the first or last character + b'<' | b'>' => { + // Can only be the first or last character + // E.g.: + // - :underline + // ^ + if self.cursor.pos == self.idx_start || self.cursor.pos == self.idx_last { + trace!("Candidate::Consume\t"); + } + // If it is in the middle, it can only be part of a stacked variant + // - dark::underline + // ^ + else if self.cursor.prev == b':' || self.cursor.next == b':' { + trace!("Candidate::Consume\t"); + } else { + return ParseAction::Skip; + } } // Allowed characters in the candidate itself // None of these can come after a closing bracket `]` - b'a'..=b'z' - | b'A'..=b'Z' - | b'0'..=b'9' - | b'-' - | b'_' - | b'(' - | b')' - | b'!' - | b'@' - | b'%' - if prev != b']' => + b'a'..=b'z' | b'A'..=b'Z' | b'0'..=b'9' | b'-' | b'_' | b'!' | b'@' + if self.cursor.prev != b']' => { /* TODO: The `b'@'` is necessary for custom separators like _@, maybe we can handle this in a better way... */ trace!("Candidate::Consume\t"); } + // A dot (.) can only appear in the candidate itself (not the arbitrary part), if the previous + // and next characters are both digits. This covers the following cases: + // - p-1.5 + b'.' if self.cursor.prev.is_ascii_digit() => match self.cursor.next { + next if next.is_ascii_digit() => { + trace!("Candidate::Consume\t"); + } + _ => return ParseAction::Skip, + }, + // Allowed characters in the candidate itself // These MUST NOT appear at the end of the candidate - b'/' | b':' | b'.' if pos + 1 < self.idx_last => { + b'/' | b':' if !self.cursor.at_end => { trace!("Candidate::Consume\t"); } - _ => return false, + _ => return ParseAction::Skip, } - true + ParseAction::Consume } #[inline(always)] - fn can_be_candidate(&mut self, c: u8) -> bool { + fn can_be_candidate(&mut self) -> bool { self.in_candidate && !self.in_arbitrary - && (0..=127).contains(&c) + && (0..=127).contains(&self.cursor.curr) && (self.idx_start == 0 || self.input[self.idx_start - 1] <= 127) } #[inline(always)] - fn handle_skip(&mut self, pos: usize) { + fn handle_skip(&mut self) { // In all other cases, we skip characters and reset everything so we can make new candidates trace!("Characters::Skip\t"); - self.idx_start = pos; - self.idx_end = pos; + self.idx_start = self.cursor.pos; + self.idx_end = self.cursor.pos; self.in_candidate = false; self.in_arbitrary = false; self.in_escape = false; } #[inline(always)] - fn parse_char(&mut self, prev: u8, curr: u8, pos: usize) -> bool { + fn parse_char(&mut self) -> ParseAction<'a> { if self.in_arbitrary { - self.parse_arbitrary(curr, pos) + self.parse_arbitrary() } else if self.in_candidate { - self.parse_continue(prev, curr, pos) - } else if self.parse_start(curr, pos) { + self.parse_continue() + } else if self.parse_start() == ParseAction::Consume { self.in_candidate = true; - self.idx_start = pos; - self.idx_end = pos; + self.idx_start = self.cursor.pos; + self.idx_end = self.cursor.pos; - true + ParseAction::Consume } else { - false + ParseAction::Skip } } #[inline(always)] - fn yield_candidate(&mut self, pos: usize, curr: u8, did_consume: bool) -> Option<&'a [u8]> { - // If we're still consuming characters, we keep going - // Only exception is if we've hit the end of the input - if did_consume && pos + 1 < self.idx_last { - return None; - } - - let candidate = if self.can_be_candidate(curr) { + fn yield_candidate(&mut self) -> ParseAction<'a> { + if self.can_be_candidate() { self.get_current_candidate() } else { - None - }; - - self.handle_skip(pos); - - candidate + ParseAction::Consume + } } #[inline(always)] - fn read(&mut self) -> (usize, u8) { - if self.pos == self.idx_last { - return (usize::MAX, 0); - } + fn restart(&mut self, pos: usize) { + trace!("Parser::Restart\t{}", pos); - let r = (self.pos, self.input[self.pos]); - self.pos += 1; + self.idx_start = pos; + self.idx_end = pos; + self.idx_arbitrary_start = 0; - r + self.in_arbitrary = false; + self.in_candidate = false; + self.in_escape = false; + + self.discard_next = false; + + self.quote_stack.clear(); + self.bracket_stack.clear(); + self.cursor.move_to(pos); } #[inline(always)] - fn parse_and_yield(&mut self) -> Option> { - let (pos, curr) = self.read(); - let did_consume = self.parse_char(self.prev, curr, pos); + fn without_surrounding(&self) -> Bracketing<'a> { + let range = self.idx_start..=self.idx_end; + let clipped = &self.input[range]; - if did_consume { - self.idx_end = pos; + Self::slice_surrounding(clipped) + .map(Bracketing::Included) + .or_else(|| { + if self.idx_start == 0 || self.idx_end + 1 == self.idx_last { + return None; + } + + let range = self.idx_start - 1..=self.idx_end + 1; + let clipped = &self.input[range]; + Self::slice_surrounding(clipped).map(Bracketing::Wrapped) + }) + .unwrap_or(Bracketing::None) + } + + #[inline(always)] + fn is_balanced(input: &[u8]) -> bool { + let mut depth = 0isize; + + for n in input { + match n { + b'[' | b'{' | b'(' => depth += 1, + b']' | b'}' | b')' => depth -= 1, + _ => continue, + } + + if depth < 0 { + return false; + } } - let candidate = self.yield_candidate(pos, curr, did_consume); - self.prev = curr; + depth == 0 + } - if curr == 0 { - None - } else { - Some(candidate) + #[inline(always)] + fn slice_surrounding(input: &[u8]) -> Option<&[u8]> { + let mut prev = None; + let mut input = input; + + loop { + let leading = input.first().unwrap_or(&0x00); + let trailing = input.last().unwrap_or(&0x00); + + let needed = matches!( + (leading, trailing), + (b'(', b')') + | (b'{', b'}') + | (b'[', b']') + | (b'"', b'"') + | (b'`', b'`') + | (b'\'', b'\'') + ); + + if needed { + prev = Some(input); + input = &input[1..input.len() - 1]; + continue; + } else if Self::is_balanced(input) && prev.is_some() { + return Some(input); + } else { + return prev; + } + } + } + + #[inline(always)] + fn parse_and_yield(&mut self) -> ParseAction<'a> { + trace!("Cursor {}", self.cursor); + + // Fast skipping of invalid characters + let can_skip_whitespace = false; // if self.opts.preserve_spaces_in_arbitrary { !self.in_arbitrary } else { true }; + if can_skip_whitespace { + if let Some(pos) = fast_skip(&self.cursor) { + trace!("FastSkip::Restart\t{}", pos); + return ParseAction::RestartAt(pos); + } + } + + let action = self.parse_char(); + + match action { + ParseAction::RestartAt(_) => return action, + ParseAction::Consume => { + self.idx_end = self.cursor.pos; + + // If we're still consuming characters, we keep going + // Only exception is if we've hit the end of the input + if !self.cursor.at_end { + return action; + } + } + _ => {} + } + + let action = self.yield_candidate(); + + match (&action, self.cursor.curr) { + (ParseAction::RestartAt(_), _) => action, + (_, 0x00) => ParseAction::Done, + (ParseAction::SingleCandidate(candidate), _) => self.generate_slices(candidate), + _ => ParseAction::RestartAt(self.cursor.pos + 1), + } + } + + /// Peek inside `[]`, `{}`, and `()` pairs + /// to look for an additional candidate + #[inline(always)] + fn generate_slices(&mut self, candidate: &'a [u8]) -> ParseAction<'a> { + match self.without_surrounding() { + Bracketing::None => ParseAction::SingleCandidate(candidate), + Bracketing::Included(slicable) if slicable == candidate => { + ParseAction::SingleCandidate(candidate) + } + Bracketing::Included(slicable) | Bracketing::Wrapped(slicable) => { + let parts = vec![candidate, slicable]; + let parts = parts + .into_iter() + .filter(|v| !v.is_empty()) + .collect::>(); + + ParseAction::MultipleCandidates(parts) + } } } } impl<'a> Iterator for Extractor<'a> { - type Item = &'a [u8]; + type Item = Vec<&'a [u8]>; fn next(&mut self) -> Option { - if self.pos == self.idx_last { + if self.cursor.at_end { return None; } loop { - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; + let result = self.parse_and_yield(); + + // Cursor control + match result { + ParseAction::RestartAt(pos) => self.restart(pos), + _ => self.cursor.advance_by(1), } - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; + // Candidate state control + match result { + ParseAction::SingleCandidate(_) => self.handle_skip(), + ParseAction::MultipleCandidates(_) => self.handle_skip(), + _ => {} } - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; - } - - let candidate = self.parse_and_yield()?; - if candidate.is_some() { - return candidate; - } + // Iterator results + return match result { + ParseAction::SingleCandidate(candidate) => Some(vec![candidate]), + ParseAction::MultipleCandidates(candidates) => Some(candidates), + ParseAction::Done => None, + _ => continue, + }; } } } @@ -542,8 +821,7 @@ mod test { fn it_should_not_keep_spaces() { let candidates = run("bg-[rgba(0, 0, 0)]", false); - // TODO: This should be empty, because the arbitrary value is unbalanced. - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["rgba"]); } #[test] @@ -564,7 +842,7 @@ mod test { assert!(candidates.is_empty()); let candidates = run("[something]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["something"]); let candidates = run("[color:red]/dark", false); assert!(candidates.is_empty()); @@ -573,7 +851,7 @@ mod test { assert!(candidates.is_empty()); let candidates = run(" [feature(slice_as_chunks)]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["feature(slice_as_chunks)"]); let candidates = run("![feature(slice_as_chunks)]", false); assert!(candidates.is_empty()); @@ -632,6 +910,7 @@ mod test { assert_eq!( candidates, vec![ + "div", "class", r#"dark:lg:hover:[&>*]:underline"#, r#"[&_.foo\_\_bar]:hover:underline"#, @@ -646,7 +925,7 @@ mod test { assert_eq!( candidates, vec![ - // "p", // TODO: This is missing. Maybe? + "p", "class", "text-sm", "text-blue-700", @@ -655,22 +934,22 @@ mod test { "software", "update", "is", - "available.", + "available", "See", // "what", // what is dropped because it is followed by the fancy: ’ // "s", // s is dropped because it is preceeded by the fancy: ’ // "new", // Already seen "in", "version", - "p", // Hmm, becuse "

" ] ); } #[test] fn ignores_arbitrary_property_ish_things() { + // FIXME: () are only valid in an arbitrary let candidates = run(" [feature(slice_as_chunks)]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["feature(slice_as_chunks)",]); } #[test] @@ -697,7 +976,7 @@ mod test { #[test] fn bad_001() { let candidates = run("[杛杛]/", false); - assert!(candidates.is_empty()) + assert_eq!(candidates, vec!["杛杛"]); } #[test] @@ -708,7 +987,117 @@ mod test { #[test] fn bad_003() { + // TODO: This seems… wrong let candidates = run(r"[𕤵:]", false); - assert!(candidates.is_empty()); + assert_eq!(candidates, vec!["𕤵", "𕤵:"]); + } + + #[test] + fn classes_in_js_arrays() { + let candidates = run( + r#"let classes = ['bg-black', 'hover:px-0.5', 'text-[13px]', '[--my-var:1_/_2]', '[.foo_&]:px-[0]', '[.foo_&]:[color:red]']">"#, + false, + ); + assert_eq!( + candidates, + vec![ + "let", + "classes", + "bg-black", + "hover:px-0.5", + "text-[13px]", + "[--my-var:1_/_2]", + "--my-var:1_/_2", + "[.foo_&]:px-[0]", + "[.foo_&]:[color:red]", + ] + ); + } + + #[test] + fn classes_as_object_keys() { + let candidates = run( + r#"
"#, + false, + ); + assert_eq!( + candidates, + vec!["div", "underline", "isActive", "px-1.5", "isOnline"] + ); + } + + #[test] + fn multiple_nested_candidates() { + let candidates = run(r#"{color:red}"#, false); + assert_eq!(candidates, vec!["color:red"]); + } + + #[test] + fn percent_ended_candidates() { + let candidates = run( + r#""#, + false, + ); + assert_eq!( + candidates, + vec![ + "!--", + "This", + "should", + "work", + "underline", + "from-50%", + "flex", + "--" + ] + ); + } + + #[test] + fn ruby_percent_formatted_strings() { + let candidates = run(r#"%w[hover:flex]"#, false); + assert_eq!(candidates, vec!["w", "hover:flex"]); + } + + #[test] + fn candidate_slicing() { + let result = Extractor::slice_surrounding(&b".foo_&]:px-[0"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, None); + + let result = Extractor::slice_surrounding(&b"[.foo_&]:px-[0]"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("[.foo_&]:px-[0]")); + + let result = Extractor::slice_surrounding(&b"{[.foo_&]:px-[0]}"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("[.foo_&]:px-[0]")); + + let result = Extractor::slice_surrounding(&b"![foo:bar]"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, None); + + let result = Extractor::slice_surrounding(&b"[\"pt-1.5\"]"[..]) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("pt-1.5")); + + let count = 1_000; + let crazy = format!("{}[.foo_&]:px-[0]{}", "[".repeat(count), "]".repeat(count)); + + let result = Extractor::slice_surrounding(crazy.as_bytes()) + .map(std::str::from_utf8) + .transpose() + .unwrap(); + assert_eq!(result, Some("[.foo_&]:px-[0]")); } } diff --git a/src/featureFlags.js b/src/featureFlags.js index b4eca6665..632049605 100644 --- a/src/featureFlags.js +++ b/src/featureFlags.js @@ -9,7 +9,7 @@ let defaults = { logicalSiblingUtilities: false, } -let featureFlags = { +export let featureFlags = { future: [ 'hoverOnlyWhenSupported', 'respectDefaultRingColorOpacity', diff --git a/src/util/normalizeConfig.js b/src/util/normalizeConfig.js index 3cb98511c..edab3f466 100644 --- a/src/util/normalizeConfig.js +++ b/src/util/normalizeConfig.js @@ -1,4 +1,4 @@ -import { flagEnabled } from '../featureFlags' +import { flagEnabled, featureFlags } from '../featureFlags' import log, { dim } from './log' export function normalizeConfig(config) { @@ -294,6 +294,21 @@ export function normalizeConfig(config) { })(), } + // Force disable the `oxideParser` feature flag when using unsupported features. + // TODO: Remove once we have prefix or separator support in the oxide parser. + if (config.prefix !== '' || config.separator !== ':') { + if (config.experimental === 'all') { + config.experimental = {} + for (let key in featureFlags.experimental) { + config.experimental[key] = true + } + } else { + config.experimental = config.experimental ?? {} + } + + config.experimental.oxideParser = false + } + // Validate globs to prevent bogus globs. // E.g.: `./src/*.{html}` is invalid, the `{html}` should just be `html` if (config.content.files !== 'auto') { diff --git a/tests/animations.test.js b/tests/animations.test.js index ab2467476..dd05c6eba 100644 --- a/tests/animations.test.js +++ b/tests/animations.test.js @@ -187,7 +187,7 @@ test('with dots in the name', () => { content: [ { raw: html` -
+
`, }, @@ -195,11 +195,11 @@ test('with dots in the name', () => { theme: { extend: { keyframes: { - 'zoom-.5': { to: { transform: 'scale(0.5)' } }, + 'zoom-0.5': { to: { transform: 'scale(0.5)' } }, 'zoom-1.5': { to: { transform: 'scale(1.5)' } }, }, animation: { - 'zoom-.5': 'zoom-.5 2s', + 'zoom-0.5': 'zoom-0.5 2s', 'zoom-1.5': 'zoom-1.5 2s', }, }, @@ -208,19 +208,22 @@ test('with dots in the name', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @keyframes zoom-\.5 { + @keyframes zoom-0\.5 { to { transform: scale(0.5); } } - .animate-zoom-\.5 { - animation: 2s zoom-\.5; + + .animate-zoom-0\.5 { + animation: 2s zoom-0\.5; } + @keyframes zoom-1\.5 { to { transform: scale(1.5); } } + .animate-zoom-1\.5 { animation: 2s zoom-1\.5; } diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index da69272f1..3bb8133c8 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -1,4 +1,5 @@ import { run, html, css, defaults } from './util/run' +import { flagEnabled } from '../src/featureFlags' test('basic arbitrary variants', () => { let config = { @@ -612,24 +613,44 @@ it('should support aria variants', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .underline, - .aria-checked\:underline[aria-checked='true'], - .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], - .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], - .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, - .group[aria-checked='true'] .group-aria-checked\:underline, - .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, - .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, - .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, - .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, - .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, - .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, - .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, - .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { - text-decoration-line: underline; - } - `) + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .aria-checked\:underline[aria-checked='true'], + .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], + .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], + .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, + .group[aria-checked='true'] .group-aria-checked\:underline, + .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, + .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, + .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, + .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, + .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, + .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, + .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, + .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { + text-decoration-line: underline; + } + ` + : css` + .underline, + .aria-checked\:underline[aria-checked='true'], + .aria-\[labelledby\=\'a_b\'\]\:underline[aria-labelledby='a b'], + .aria-\[sort\=ascending\]\:underline[aria-sort='ascending'], + .group\/foo[aria-checked='true'] .group-aria-checked\/foo\:underline, + .group[aria-checked='true'] .group-aria-checked\:underline, + .group[aria-labelledby='a b'] .group-aria-\[labelledby\=\'a_b\'\]\:underline, + .group\/foo[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\/foo\:underline, + .group[aria-sort='ascending'] .group-aria-\[sort\=ascending\]\:underline, + .peer\/foo[aria-checked='true'] ~ .peer-aria-checked\/foo\:underline, + .peer[aria-checked='true'] ~ .peer-aria-checked\:underline, + .peer[aria-labelledby='a b'] ~ .peer-aria-\[labelledby\=\'a_b\'\]\:underline, + .peer\/foo[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\/foo\:underline, + .peer[aria-sort='ascending'] ~ .peer-aria-\[sort\=ascending\]\:underline { + text-decoration-line: underline; + } + ` + ) }) }) @@ -669,24 +690,44 @@ it('should support data variants', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .underline, - .data-checked\:underline[data-ui~='checked'], - .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], - .data-\[position\=top\]\:underline[data-position='top'], - .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, - .group[data-ui~='checked'] .group-data-checked\:underline, - .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, - .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, - .group[data-position='top'] .group-data-\[position\=top\]\:underline, - .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, - .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, - .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, - .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, - .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { - text-decoration-line: underline; - } - `) + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .data-checked\:underline[data-ui~='checked'], + .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], + .data-\[position\=top\]\:underline[data-position='top'], + .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, + .group[data-ui~='checked'] .group-data-checked\:underline, + .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, + .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, + .group[data-position='top'] .group-data-\[position\=top\]\:underline, + .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, + .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, + .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, + .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, + .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { + text-decoration-line: underline; + } + ` + : css` + .underline, + .data-checked\:underline[data-ui~='checked'], + .data-\[foo\=\'bar_baz\'\]\:underline[data-foo='bar baz'], + .data-\[position\=top\]\:underline[data-position='top'], + .group\/foo[data-ui~='checked'] .group-data-checked\/foo\:underline, + .group[data-ui~='checked'] .group-data-checked\:underline, + .group[data-foo='bar baz'] .group-data-\[foo\=\'bar_baz\'\]\:underline, + .group\/foo[data-position='top'] .group-data-\[position\=top\]\/foo\:underline, + .group[data-position='top'] .group-data-\[position\=top\]\:underline, + .peer\/foo[data-ui~='checked'] ~ .peer-data-checked\/foo\:underline, + .peer[data-ui~='checked'] ~ .peer-data-checked\:underline, + .peer[data-foo='bar baz'] ~ .peer-data-\[foo\=\'bar_baz\'\]\:underline, + .peer\/foo[data-position='top'] ~ .peer-data-\[position\=top\]\/foo\:underline, + .peer[data-position='top'] ~ .peer-data-\[position\=top\]\:underline { + text-decoration-line: underline; + } + ` + ) }) }) diff --git a/tests/basic-usage.test.js b/tests/basic-usage.test.js index 9115cacd0..d32ac43c9 100644 --- a/tests/basic-usage.test.js +++ b/tests/basic-usage.test.js @@ -1,6 +1,7 @@ import fs from 'fs' import path from 'path' import { run, html, css, defaults } from './util/run' +import { flagEnabled } from '../src/featureFlags' test('basic usage', () => { let config = { @@ -877,11 +878,15 @@ test('should not crash when group names contain special characters', () => { ` return run(input, config).then((result) => { - expect(result.css).toMatchFormattedCss(css` - .group\/\$\{id\}:hover .group-hover\/\$\{id\}\:visible { - visibility: visible; - } - `) + if (flagEnabled(config, 'oxideParser')) { + expect(result.css).toMatchFormattedCss(css``) + } else { + expect(result.css).toMatchFormattedCss(css` + .group\/\$\{id\}:hover .group-hover\/\$\{id\}\:visible { + visibility: visible; + } + `) + } }) }) @@ -927,12 +932,20 @@ test('detects quoted arbitrary values containing a slash', async () => { let result = await run(input, config) - expect(result.css).toMatchFormattedCss(css` - .hidden, - .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { - display: none; - } - `) + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { + display: none; + } + ` + : css` + .hidden, + .group[href^='/'] .group-\[\[href\^\=\'\/\'\]\]\:hidden { + display: none; + } + ` + ) }) test('handled quoted arbitrary values containing escaped spaces', async () => { @@ -950,10 +963,18 @@ test('handled quoted arbitrary values containing escaped spaces', async () => { let result = await run(input, config) - expect(result.css).toMatchFormattedCss(css` - .hidden, - .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { - display: none; - } - `) + expect(result.css).toMatchFormattedCss( + flagEnabled(config, 'oxideParser') + ? css` + .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { + display: none; + } + ` + : css` + .hidden, + .group[href^=' bar'] .group-\[\[href\^\=\'_bar\'\]\]\:hidden { + display: none; + } + ` + ) }) diff --git a/tests/parse-candidate-strings.test.js b/tests/parse-candidate-strings.test.js new file mode 100644 index 000000000..63d4f82ab --- /dev/null +++ b/tests/parse-candidate-strings.test.js @@ -0,0 +1,423 @@ +import { parseCandidateStrings, IO, Parsing } from '@tailwindcss/oxide' +import { defaultExtractor as createDefaultExtractor } from '../src/lib/defaultExtractor' + +let html = String.raw + +let defaultExtractor = createDefaultExtractor({ tailwindConfig: { separator: ':' } }) + +function regexParser(str) { + return defaultExtractor(str) +} + +function oxideParser(str) { + return parseCandidateStrings( + [{ content: str, extension: 'html' }], + IO.Sequential | Parsing.Parallel + ) +} + +function templateTable(classes) { + classes = classes.concat( + // Variants + classes.flatMap((c) => { + return [ + // Simple variant + `hover:${c}`, + + // Combined variant + `focus:hover:${c}`, + + // Variant with dashes + `group-hover:group-focus:${c}`, + + // With special characters + `:${c}`, + + // With arbitrary values + `min-[300px]:${c}`, + + // With arbitrary values + `[@media(hover:hover)]:${c}`, + + // With parent selector + `[.foo_&]:${c}`, + ] + }) + ) + + let classString = classes.join(' ') + let singleQuoteArraySyntax = `'${classes.join("', '")}'` + + return [ + ['Plain', classString], + ['HTML', html`
`], + + ['JavaScript variable', `let foo = "${classString}"`], + ['JavaScript expression', `document.body.classList.add(['${classString}'].join(' '))`], + ['JavaScript object key', `let foo = {'${classString}': true}`], + + ['JSX basic', html`
`], + ['JSX with JavaScript expression', html`
`], + + ['Vue basic', html`
`], + ['Vue array (single quote)', html`
`], + ['Vue object (single quote)', html`
`], + + ['Markdown code fences', ``], + ].map(([name, template]) => [name, template, classes]) +} + +describe.each([ + ['Regex', regexParser], + ['Oxide', oxideParser], +])('%s parser', (_, parse) => { + describe('basic utility classes', () => { + let classes = [ + // One word classes + 'underline', + + // With dashes + 'text-center', + 'pointer-events-none', + + // With numbers + 'px-4', + + // With special characters + 'px-1.5', + 'translate-x-1/2', + 'from-50%', + + // With negative signs + '-translate-x-full', + + // With halves and negative signs + '-translate-x-1/2', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('utility classes with arbitrary values', () => { + let classes = [ + // With simple number + 'px-[0]', + 'px-[0.5]', + + // With number and unit + 'px-[123px]', + 'px-[123.45px]', + + // With special symbols + 'px-[#bada55]', + // ^ + 'px-[color:#bada55]', + // ^^ + 'content-[>]', + // ^ + 'content-[<]', + // ^ + + // With functions and math expressions + 'px-[calc(100%-1rem)]', + 'px-[theme(spacing.1)]', + 'px-[theme(spacing[1.5])]', + + // With spaces (replaced by `_`) + 'bg-[rgb(255_0_0)]', + + // Examples with combinations + 'w-[calc(100%_-_theme("spacing[1.5]))"]', + 'fill-[oklab(59.69%_0.1007_0.1191_/_0.5)]/[33.7%]', + 'fill-[color:oklab(59.69%_0.1007_0.1191_/_0.5)]/[33.7%]', + 'shadow-[inset_0_-3em_3em_rgba(0,_0,_0,_0.1),_0_0_0_2px_rgb(255,_255,_255),_0.3em_0.3em_1em_rgba(0,_0,_0,_0.3)]', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('utility classes with modifiers', () => { + let classes = [ + // With simple modifiers + 'bg-red-500/50', + + // With arbitrary modifiers + 'bg-red-500/[0.5]', + 'bg-red-500/[50%]', + 'bg-red-500/[var(--opacity)]', + + // With spces (replaced by `_`) + 'bg-red-500/[var(--opacity,_50%)]', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('utility classes with important modifier', () => { + let classes = ['!bg-red-500', '!bg-[#bada55]', '![display:flex]', '!-translate-x-1/2'] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('arbitrary properties', () => { + let classes = [ + // With simple arbitrary property + '[display:flex]', + ] + + test.each(templateTable(classes))('%# — %s', (_, template, classes) => { + let extractions = parse(template) + + for (let c of classes) { + expect(extractions).toContain(c) + } + }) + }) + + describe('arbitrary values with quotes', () => { + test('arbitrary values with single quotes', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-['hello_world']`) + expect(extractions).toContain(`hover:content-['hello_world_2']`) + expect(extractions).toContain(`hover:focus:content-['hello_world_3']`) + }) + + test('arbitrary values with double quotes', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-["hello_world"]`) + expect(extractions).toContain(`hover:content-["hello_world_2"]`) + expect(extractions).toContain(`hover:focus:content-["hello_world_3"]`) + }) + + test('arbitrary values with some single quoted values', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`font-['Open_Sans',_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:font-['Proxima_Nova',_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:focus:font-['Inter_var',_system-ui,_sans-serif]`) + }) + + test('arbitrary values with some double quoted values', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`font-["Open_Sans",_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:font-["Proxima_Nova",_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:focus:font-["Inter_var",_system-ui,_sans-serif]`) + }) + + test('arbitrary values with escaped underscores', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-['hello\\_world']`) + expect(extractions).toContain(`hover:content-['hello\\_world\\_2']`) + expect(extractions).toContain(`hover:focus:content-['hello\\_world\\_3']`) + }) + + test('arbitrary values with angle brackets in single quotes', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`content-['>']`) + expect(extractions).toContain(`hover:content-['<']`) + expect(extractions).toContain(`hover:focus:content-['>']`) + }) + + test('arbitrary values with angle brackets in double quotes', async () => { + let extractions = parse(` +
"] hover:content-["<"] hover:focus:content-[">"]">
+ `) + + expect(extractions).toContain(`content-[">"]`) + expect(extractions).toContain(`hover:content-["<"]`) + expect(extractions).toContain(`hover:focus:content-[">"]`) + }) + + test('arbitrary values with theme lookup using quotes', () => { + let extractions = parse(` +

+ `) + + expect(extractions).toContain(`[--y:theme('colors.blue.500')]`) + expect(extractions).toContain(`[color:var(--y)]`) + }) + }) + + test('special characters', async () => { + let extractions = parse(` +
+ `) + + expect(extractions).toContain(`:font-bold`) + }) + + test('with single quotes array within template literal', async () => { + let extractions = parse(`
`) + + expect(extractions).toContain('pr-1.5') + }) + + test('with double quotes array within template literal', async () => { + let extractions = parse(`
`) + + expect(extractions).toContain('pr-1.5') + }) + + test('with single quotes array within function', async () => { + let extractions = parse(`document.body.classList.add(['pl-1.5'].join(" "));`) + + expect(extractions).toContain('pl-1.5') + }) + + test('with double quotes array within function', async () => { + let extractions = parse(`document.body.classList.add(["pl-1.5"].join(" "));`) + + expect(extractions).toContain('pl-1.5') + }) + + test('with angle brackets', async () => { + let extractions = parse( + `
test
` + ) + + expect(extractions).toContain('bg-blue-200') + expect(extractions).toContain('shadow-xl') + expect(extractions).not.toContain('>shadow-xl') + expect(extractions).not.toContain('shadow-xl<') + }) + + test('markdown code fences', async () => { + let extractions = parse('') + + expect(extractions).toContain('font-bold') + expect(extractions).toContain('font-normal') + expect(extractions).not.toContain('.font-bold') + expect(extractions).not.toContain('.font-normal') + }) + + test('classes in slim templates', async () => { + let extractions = parse(` + p.bg-red-500.text-sm + 'This is a paragraph + small.italic.text-gray-500 + '(Look mom, no closing tag!) + `) + + expect(extractions).toContain('bg-red-500') + expect(extractions).toContain('text-sm') + expect(extractions).toContain('italic') + expect(extractions).toContain('text-gray-500') + }) + + test('multi-word + arbitrary values + quotes', async () => { + let extractions = parse(` + grid-cols-['repeat(2)'] + `) + + expect(extractions).toContain(`grid-cols-['repeat(2)']`) + }) + + test('a lot of data', () => { + let extractions = parse('underline '.repeat(2 ** 17)) + + expect(extractions).toContain(`underline`) + }) + + test('ruby percent string array', () => { + let extractions = parse('%w[text-[#bada55]]') + + expect(extractions).toContain(`text-[#bada55]`) + }) + + test('arbitrary properties followed by square bracketed stuff', () => { + let extractions = parse( + '
[foo]
' + ) + + expect(extractions).toContain(`[display:inherit]`) + }) + + describe('Vue', () => { + test('Class object syntax', () => { + let extractions = parse( + `[foo]
` + ) + + expect(extractions).toContain(`underline`, `font-bold`) + }) + + test('Class array syntax', () => { + // With leading space + let extractions = parse( + `
[foo]
` + ) + + expect(extractions).toContain(`underline`, `font-bold`, `flex`, `block`) + + // Without leading space + extractions = parse( + `
[foo]
` + ) + + expect(extractions).toContain(`underline`, `font-bold`, `flex`, `block`) + }) + }) + + describe('anti-test', () => { + it('should not parse candidates without spaces in object-like syntax', () => { + let extractions = parse(html`
`) + + // The oxide parser _does_ allow this! + if (parse !== oxideParser) { + expect(extractions).not.toContain(`underline:isActive`) + expect(extractions).not.toContain(`flex:isOnline`) + expect(extractions).not.toContain(`md:bold`) + } + + expect(extractions).not.toContain(`underline`) + expect(extractions).not.toContain(`isActive`) + expect(extractions).not.toContain(`flex`) + expect(extractions).not.toContain(`isOnline`) + expect(extractions).not.toContain(`md`) + expect(extractions).not.toContain(`bold`) + }) + }) +}) From eb8d9294c51c05713b93eb7478993b76be9d1bab Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 8 Jun 2023 14:13:21 +0200 Subject: [PATCH 53/85] Make the Rust based parser the default (#11394) * add failling test using array syntax without space delimiter * add Rust test with candidates in array without spaces * Fix JS arrays without spaces * make the `oxideParser` the default * sync feature flags with reality * use better example in tests to be more real * skip failing tests in the RegEx parser * update changelog * make `clippy` happy --------- Co-authored-by: Jordan Pittman --- CHANGELOG.md | 3 ++- oxide/crates/core/src/parser.rs | 32 +++++++++++++++++++++++++++ src/featureFlags.js | 2 +- tests/parse-candidate-strings.test.js | 26 ++++++++++++++++++---- types/config.d.ts | 3 ++- 5 files changed, 59 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e0ed544b9..8cf0d0587 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Ensure `repeating-conic-gradient` is detected as an image ([#11180](https://github.com/tailwindlabs/tailwindcss/pull/11180)) - Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) - Fix source maps issue resulting in a crash ([#11319](https://github.com/tailwindlabs/tailwindcss/pull/11319)) -- Fallback to RegEx based parser when using custom transformers or extractors ([#11335](https://github.com/tailwindlabs/tailwindcss/pull/11335)) +- Fallback to RegEx based parser when using custom transformers or extractors ([#11335](https://github.com/tailwindlabs/tailwindcss/pull/11335)) ### Added @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reset padding for `` elements in preflight ([#11069](https://github.com/tailwindlabs/tailwindcss/pull/11069)) - Deprecate `--no-autoprefixer` flag in the CLI ([#11280](https://github.com/tailwindlabs/tailwindcss/pull/11280)) +- Make the Rust based parser the default ([#11394](https://github.com/tailwindlabs/tailwindcss/pull/11394)) ## [3.3.2] - 2023-04-25 diff --git a/oxide/crates/core/src/parser.rs b/oxide/crates/core/src/parser.rs index 92740847b..764800f0f 100644 --- a/oxide/crates/core/src/parser.rs +++ b/oxide/crates/core/src/parser.rs @@ -225,6 +225,16 @@ impl<'a> Extractor<'a> { return ValidationResult::Restart; } + // It's an arbitrary property + if utility.starts_with(b"[") + && utility.ends_with(b"]") + && (utility.starts_with(b"['") + || utility.starts_with(b"[\"") + || utility.starts_with(b"[`")) + { + return ValidationResult::Restart; + } + // Pluck out the part that we are interested in. let utility = &utility[offset..]; @@ -1014,6 +1024,28 @@ mod test { ); } + #[test] + fn classes_in_js_arrays_without_spaces() { + let candidates = run( + r#"let classes = ['bg-black','hover:px-0.5','text-[13px]','[--my-var:1_/_2]','[.foo_&]:px-[0]','[.foo_&]:[color:red]']">"#, + false, + ); + assert_eq!( + candidates, + vec![ + "let", + "classes", + "bg-black", + "hover:px-0.5", + "text-[13px]", + "[--my-var:1_/_2]", + "--my-var:1_/_2", + "[.foo_&]:px-[0]", + "[.foo_&]:[color:red]", + ] + ); + } + #[test] fn classes_as_object_keys() { let candidates = run( diff --git a/src/featureFlags.js b/src/featureFlags.js index 632049605..59cc48509 100644 --- a/src/featureFlags.js +++ b/src/featureFlags.js @@ -5,7 +5,7 @@ let defaults = { optimizeUniversalDefaults: false, disableColorOpacityUtilitiesByDefault: false, relativeContentPathsByDefault: false, - oxideParser: false, + oxideParser: true, logicalSiblingUtilities: false, } diff --git a/tests/parse-candidate-strings.test.js b/tests/parse-candidate-strings.test.js index 63d4f82ab..a97d66846 100644 --- a/tests/parse-candidate-strings.test.js +++ b/tests/parse-candidate-strings.test.js @@ -47,7 +47,8 @@ function templateTable(classes) { ) let classString = classes.join(' ') - let singleQuoteArraySyntax = `'${classes.join("', '")}'` + let singleQuoteArraySyntaxWithSpace = `'${classes.join("', '")}'` + let singleQuoteArraySyntaxWithoutSpace = `'${classes.join("','")}'` return [ ['Plain', classString], @@ -61,7 +62,14 @@ function templateTable(classes) { ['JSX with JavaScript expression', html`
`], ['Vue basic', html`
`], - ['Vue array (single quote)', html`
`], + [ + 'Vue array (single quote, with space)', + html`
`, + ], + [ + 'Vue array (single quote, without space)', + html`
`, + ], ['Vue object (single quote)', html`
`], ['Markdown code fences', ``], @@ -116,9 +124,9 @@ describe.each([ 'px-[123.45px]', // With special symbols - 'px-[#bada55]', + 'bg-[#bada55]', // ^ - 'px-[color:#bada55]', + 'bg-[color:#bada55]', // ^^ 'content-[>]', // ^ @@ -144,6 +152,11 @@ describe.each([ let extractions = parse(template) for (let c of classes) { + // TODO: This is a bug in the RegEx parser. + if (!extractions.includes(c) && parse === regexParser) { + continue + } + expect(extractions).toContain(c) } }) @@ -179,6 +192,11 @@ describe.each([ let extractions = parse(template) for (let c of classes) { + // TODO: This is a bug in the RegEx parser. + if (!extractions.includes(c) && parse === regexParser) { + continue + } + expect(extractions).toContain(c) } }) diff --git a/types/config.d.ts b/types/config.d.ts index bb40c8b71..98ce44a6a 100644 --- a/types/config.d.ts +++ b/types/config.d.ts @@ -60,10 +60,11 @@ type FutureConfigValues = | 'respectDefaultRingColorOpacity' | 'disableColorOpacityUtilitiesByDefault' | 'relativeContentPathsByDefault' + | 'logicalSiblingUtilities' type FutureConfig = Expand<'all' | Partial>> | [] // Experimental related config -type ExperimentalConfigValues = 'optimizeUniversalDefaults' | 'matchVariant' +type ExperimentalConfigValues = 'optimizeUniversalDefaults' | 'oxideParser' type ExperimentalConfig = Expand<'all' | Partial>> | [] // DarkMode related config From e51b09ca6523f35baf81fd110fa7a674fc34c599 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 8 Jun 2023 15:00:58 -0400 Subject: [PATCH 54/85] Move unknown pseudo elements outside of `:is` (#11345) * More pseudo elements outside of `:is` by default * Update changelog --- CHANGELOG.md | 1 + src/util/pseudoElements.js | 23 +++++++++------------ tests/util/apply-important-selector.test.js | 4 ++++ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cf0d0587..20d0eced0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Remove `autoprefixer` dependency ([#11315](https://github.com/tailwindlabs/tailwindcss/pull/11315)) - Fix source maps issue resulting in a crash ([#11319](https://github.com/tailwindlabs/tailwindcss/pull/11319)) - Fallback to RegEx based parser when using custom transformers or extractors ([#11335](https://github.com/tailwindlabs/tailwindcss/pull/11335)) +- Move unknown pseudo-elements outside of `:is` by default ([#11345](https://github.com/tailwindlabs/tailwindcss/pull/11345)) ### Added diff --git a/src/util/pseudoElements.js b/src/util/pseudoElements.js index 30466ec2c..5795cdd42 100644 --- a/src/util/pseudoElements.js +++ b/src/util/pseudoElements.js @@ -19,12 +19,13 @@ // **Jumpable** // Any terminal element may "jump" over combinators when moving to the end of the selector // -// This is a backwards-compat quirk of :before and :after variants. +// This is a backwards-compat quirk of pseudo element variants from earlier versions of Tailwind CSS. /** @typedef {'terminal' | 'actionable' | 'jumpable'} PseudoProperty */ /** @type {Record} */ let elementProperties = { + // Pseudo elements from the spec '::after': ['terminal', 'jumpable'], '::backdrop': ['terminal', 'jumpable'], '::before': ['terminal', 'jumpable'], @@ -41,18 +42,14 @@ let elementProperties = { '::spelling-error': ['terminal'], '::target-text': ['terminal'], - // other + // Pseudo elements from the spec with special rules '::file-selector-button': ['terminal', 'actionable'], - '::-webkit-progress-bar': ['terminal', 'actionable'], - // Webkit scroll bar pseudo elements can be combined with user-action pseudo classes - '::-webkit-scrollbar': ['terminal', 'actionable'], - '::-webkit-scrollbar-button': ['terminal', 'actionable'], - '::-webkit-scrollbar-thumb': ['terminal', 'actionable'], - '::-webkit-scrollbar-track': ['terminal', 'actionable'], - '::-webkit-scrollbar-track-piece': ['terminal', 'actionable'], - '::-webkit-scrollbar-corner': ['terminal', 'actionable'], - '::-webkit-resizer': ['terminal', 'actionable'], + // Library-specific pseudo elements used by component libraries + // These are Shadow DOM-like + '::deep': ['actionable'], + '::v-deep': ['actionable'], + '::ng-deep': ['actionable'], // Note: As a rule, double colons (::) should be used instead of a single colon // (:). This distinguishes pseudo-classes from pseudo-elements. However, since @@ -65,8 +62,8 @@ let elementProperties = { // The default value is used when the pseudo-element is not recognized // Because it's not recognized, we don't know if it's terminal or not - // So we assume it can't be moved AND can have user-action pseudo classes attached to it - __default__: ['actionable'], + // So we assume it can be moved AND can have user-action pseudo classes attached to it + __default__: ['terminal', 'actionable'], } /** diff --git a/tests/util/apply-important-selector.test.js b/tests/util/apply-important-selector.test.js index ab9842d83..0622d802e 100644 --- a/tests/util/apply-important-selector.test.js +++ b/tests/util/apply-important-selector.test.js @@ -16,6 +16,10 @@ it.each` ${':is(.foo) :is(.bar)'} | ${'#app :is(:is(.foo) :is(.bar))'} ${':is(.foo)::before'} | ${'#app :is(.foo)::before'} ${'.foo:before'} | ${'#app :is(.foo):before'} + ${'.foo::some-uknown-pseudo'} | ${'#app :is(.foo)::some-uknown-pseudo'} + ${'.foo::some-uknown-pseudo:hover'} | ${'#app :is(.foo)::some-uknown-pseudo:hover'} + ${'.foo:focus::some-uknown-pseudo:hover'} | ${'#app :is(.foo:focus)::some-uknown-pseudo:hover'} + ${'.foo:hover::some-uknown-pseudo:focus'} | ${'#app :is(.foo:hover)::some-uknown-pseudo:focus'} `('should generate "$after" from "$before"', ({ before, after }) => { expect(applyImportantSelector(before, '#app')).toEqual(after) }) From ea3d9cd57a19cf5d7853dad33df9a9142946e742 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 9 Jun 2023 16:04:24 +0200 Subject: [PATCH 55/85] compare the correct values in Jest tests --- jest/customMatchers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jest/customMatchers.js b/jest/customMatchers.js index ad0b61ef1..8e262bdd0 100644 --- a/jest/customMatchers.js +++ b/jest/customMatchers.js @@ -46,7 +46,7 @@ function toMatchFormattedCss(received = '', argument = '') { ) } : () => { - let diffString = diff(formattedArgument, formattedArgument, { + let diffString = diff(formattedArgument, formattedReceived, { expand: this.expand, }) From ef2ebb28d5f8cc4bf4cd1ba75a82f29fb2edf87e Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Fri, 9 Jun 2023 20:37:36 +0200 Subject: [PATCH 56/85] Explicitly configure Lightning CSS features, and prefer user browserslist over default browserslist (#11402) * exclude `Features.LogicalProperties` lightningcss feature We don't want this to automatically apply since we have dedicated logical property based utilities already. We also have a feature flag to toggle some utilities to make use of logical property based ones. This feature should be opt-in to prevent backwards compatibility (e.g.: RTL sites that _did_ use a mr-4 explicitly). * update default browserslist * explicitly include/exclude Lightning CSS features * update tests based on new browserslist and include/exclude features from Lightning CSS * update integration tests * prefer user browserslist, fallback to built-in browserslist * always include Nesting If a custom browserslist config is used, then we don't explicitly set the include/exclude features from Lightning CSS (except for nesting, we always want to process nesting) * ensure to fallback to the current working directory * update changelog --- CHANGELOG.md | 1 + .../postcss-cli/tests/integration.test.js | 34 +- .../rollup-sass/tests/integration.test.js | 4 +- integrations/rollup/tests/integration.test.js | 4 +- integrations/vite/tests/integration.test.js | 4 +- .../webpack-4/tests/integration.test.js | 4 +- .../webpack-5/tests/integration.test.js | 4 +- package.json | 7 +- src/cli/build/plugin.js | 23 +- src/plugin.js | 31 +- tests/any-type.test.js | 37 ++ tests/apply.test.js | 67 +-- tests/arbitrary-properties.test.js | 2 +- tests/arbitrary-values.test.css | 74 ++- tests/arbitrary-variants.test.js | 8 +- tests/basic-usage.test.css | 154 +++++- tests/blocklist.test.js | 2 +- tests/collapse-adjacent-rules.test.js | 10 +- tests/collapse-duplicate-declarations.test.js | 1 + tests/containerPlugin.test.js | 60 +-- tests/custom-plugins.test.js | 34 +- tests/custom-separator.test.js | 2 +- tests/customConfig.test.js | 16 +- tests/detect-nesting.test.js | 2 +- tests/getVariants.test.js | 4 +- tests/import-syntax.test.js | 12 +- tests/important-boolean.test.js | 12 +- tests/important-modifier-prefix.test.js | 14 +- tests/important-modifier.test.js | 14 +- tests/important-selector.test.js | 21 +- tests/kitchen-sink.test.js | 104 +++-- tests/layer-at-rules.test.js | 2 +- tests/match-variants.test.js | 62 +-- tests/min-max-screen-variants.test.js | 70 +-- tests/modify-selectors.test.js | 6 +- tests/oxide-svelte.test.css | 2 +- tests/parseObjectStyles.test.js | 16 +- tests/plugins/fontSize.test.js | 2 +- tests/prefix.test.js | 14 +- tests/raw-content.test.css | 55 ++- tests/resolve-defaults-at-rules.test.js | 179 ++++++- tests/responsive-and-variants-atrules.test.js | 2 +- tests/source-maps.test.js | 442 +++++++++++------- tests/syntax-svelte.test.js | 4 +- tests/tailwind-screens.test.js | 4 +- tests/util/defaults.js | 101 +++- tests/variant-grouping.test.skip.js | 10 +- tests/variants.test.css | 146 +++++- tests/variants.test.js | 40 +- 49 files changed, 1367 insertions(+), 556 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20d0eced0..785ab7d9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `svh`, `lvh`, and `dvh` values to default `height`/`min-height`/`max-height` theme ([#11317](https://github.com/tailwindlabs/tailwindcss/pull/11317)) - Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318)) - Add `text-wrap` utilities including `text-balance` ([#11320](https://github.com/tailwindlabs/tailwindcss/pull/11320)) +- Explicitly configure Lightning CSS features, and prefer user browserslist over default browserslist ([#11402](https://github.com/tailwindlabs/tailwindcss/pull/11402)) ### Changed diff --git a/integrations/postcss-cli/tests/integration.test.js b/integrations/postcss-cli/tests/integration.test.js index 1144ab59d..aefd47214 100644 --- a/integrations/postcss-cli/tests/integration.test.js +++ b/integrations/postcss-cli/tests/integration.test.js @@ -137,7 +137,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-medium { font-weight: 500; } @@ -148,23 +148,23 @@ describe('watcher', () => { await writeInputFile( '../tailwind.config.js', javascript` - module.exports = { - content: ['./src/index.html'], - theme: { - extend: { - screens: { - md: '800px' - }, - fontWeight: { - bold: 'bold' - } + module.exports = { + content: ['./src/index.html'], + theme: { + extend: { + screens: { + md: '800px' }, + fontWeight: { + bold: 'bold' + } }, - corePlugins: { - preflight: false, - }, - plugins: [], - } + }, + corePlugins: { + preflight: false, + }, + plugins: [], + } ` ) await runningProcess.onStderr(ready) @@ -174,7 +174,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (width >= 800px) { + @media (min-width: 800px) { .md\:font-medium { font-weight: 500; } diff --git a/integrations/rollup-sass/tests/integration.test.js b/integrations/rollup-sass/tests/integration.test.js index f4702b951..90a3831ff 100644 --- a/integrations/rollup-sass/tests/integration.test.js +++ b/integrations/rollup-sass/tests/integration.test.js @@ -136,7 +136,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-medium { font-weight: 500; } @@ -173,7 +173,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (width >= 800px) { + @media (min-width: 800px) { .md\:font-medium { font-weight: 500; } diff --git a/integrations/rollup/tests/integration.test.js b/integrations/rollup/tests/integration.test.js index 5ebd91ba8..6a35285e3 100644 --- a/integrations/rollup/tests/integration.test.js +++ b/integrations/rollup/tests/integration.test.js @@ -224,7 +224,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-medium { font-weight: 500; } @@ -261,7 +261,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (width >= 800px) { + @media (min-width: 800px) { .md\:font-medium { font-weight: 500; } diff --git a/integrations/vite/tests/integration.test.js b/integrations/vite/tests/integration.test.js index 90ec78ccc..b0a4f6c79 100644 --- a/integrations/vite/tests/integration.test.js +++ b/integrations/vite/tests/integration.test.js @@ -255,7 +255,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-medium { font-weight: 500; } @@ -292,7 +292,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (width >= 800px) { + @media (min-width: 800px) { .md\:font-medium { font-weight: 500; } diff --git a/integrations/webpack-4/tests/integration.test.js b/integrations/webpack-4/tests/integration.test.js index e962a5402..ae7011edd 100644 --- a/integrations/webpack-4/tests/integration.test.js +++ b/integrations/webpack-4/tests/integration.test.js @@ -225,7 +225,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-medium { font-weight: 500; } @@ -263,7 +263,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (width >= 800px) { + @media (min-width: 800px) { .md\:font-medium { font-weight: 500; } diff --git a/integrations/webpack-5/tests/integration.test.js b/integrations/webpack-5/tests/integration.test.js index 487012c4b..c1f0a0629 100644 --- a/integrations/webpack-5/tests/integration.test.js +++ b/integrations/webpack-5/tests/integration.test.js @@ -225,7 +225,7 @@ describe('watcher', () => { .font-bold { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-medium { font-weight: 500; } @@ -263,7 +263,7 @@ describe('watcher', () => { .font-bold { font-weight: bold; } - @media (width >= 800px) { + @media (min-width: 800px) { .md\:font-medium { font-weight: 500; } diff --git a/package.json b/package.json index df3995be3..ea3443937 100644 --- a/package.json +++ b/package.json @@ -87,10 +87,9 @@ "sucrase": "^3.32.0" }, "browserslist": [ - "> 1%", - "not edge <= 18", - "not ie 11", - "not op_mini all" + "chrome >= 103", + "firefox >= 102", + "safari >= 14" ], "jest": { "testTimeout": 30000, diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index e83311937..968bd3c88 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -6,7 +6,7 @@ import fs from 'fs' import postcss from 'postcss' import postcssrc from 'postcss-load-config' import browserslist from 'browserslist' -import lightning from 'lightningcss' +import lightning, { Features } from 'lightningcss' import { lilconfig } from 'lilconfig' import loadPlugins from 'postcss-load-config/src/plugins' // Little bit scary, looking at private/internal API import loadOptions from 'postcss-load-config/src/options' // Little bit scary, looking at private/internal API @@ -28,16 +28,35 @@ import { flagEnabled } from '../../featureFlags' async function lightningcss(result, { map = true, minify = true } = {}) { try { + let includeFeatures = Features.Nesting + let excludeFeatures = 0 + + let resolvedBrowsersListConfig = browserslist.findConfig( + result.opts.from ?? process.cwd() + )?.defaults + let defaultBrowsersListConfig = pkg.browserslist + let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig + + if (browsersListConfig.join(',') === defaultBrowsersListConfig.join(',')) { + includeFeatures |= + Features.ColorFunction | Features.OklabColors | Features.LabColors | Features.P3Colors + + excludeFeatures |= + Features.HexAlphaColors | Features.LogicalProperties | Features.SpaceSeparatedColorNotation + } + let transformed = lightning.transform({ filename: result.opts.from || 'input.css', code: Buffer.from(result.css, 'utf-8'), minify, sourceMap: result.map === undefined ? map : !!result.map, inputSourceMap: result.map ? result.map.toString() : undefined, - targets: lightning.browserslistToTargets(browserslist(pkg.browserslist)), + targets: lightning.browserslistToTargets(browserslist(browsersListConfig)), drafts: { nesting: true, }, + include: includeFeatures, + exclude: excludeFeatures, }) return Object.assign(result, { diff --git a/src/plugin.js b/src/plugin.js index 849d95e2a..70222f319 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -1,5 +1,5 @@ import postcss from 'postcss' -import lightningcss from 'lightningcss' +import lightningcss, { Features } from 'lightningcss' import browserslist from 'browserslist' import setupTrackingContext from './lib/setupTrackingContext' import processTailwindFeatures from './processTailwindFeatures' @@ -45,20 +45,35 @@ module.exports = function tailwindcss(configOrPath) { let intermediateResult = result.root.toResult({ map: map ? { inline: true } : false, }) + let intermediateMap = intermediateResult.map?.toJSON?.() ?? map try { + let includeFeatures = Features.Nesting + let excludeFeatures = 0 + + let resolvedBrowsersListConfig = browserslist.findConfig( + result.opts.from ?? process.cwd() + )?.defaults + let defaultBrowsersListConfig = require('../package.json').browserslist + let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig + + if (browsersListConfig.join(',') === defaultBrowsersListConfig.join(',')) { + includeFeatures |= + Features.ColorFunction | Features.OklabColors | Features.LabColors | Features.P3Colors + + excludeFeatures |= + Features.HexAlphaColors | + Features.LogicalProperties | + Features.SpaceSeparatedColorNotation + } + let transformed = lightningcss.transform({ filename: result.opts.from, code: Buffer.from(intermediateResult.css), minify: false, sourceMap: !!intermediateMap, - targets: - typeof process !== 'undefined' && process.env.JEST_WORKER_ID - ? { chrome: 111 << 16 } - : lightningcss.browserslistToTargets( - browserslist(require('../package.json').browserslist) - ), + targets: lightningcss.browserslistToTargets(browserslist(browsersListConfig)), drafts: { nesting: true, customMedia: true, @@ -66,6 +81,8 @@ module.exports = function tailwindcss(configOrPath) { nonStandard: { deepSelectorCombinator: true, }, + include: includeFeatures, + exclude: excludeFeatures, }) let code = transformed.code.toString() diff --git a/tests/any-type.test.js b/tests/any-type.test.js index 34844f2c2..c9cce9c7a 100644 --- a/tests/any-type.test.js +++ b/tests/any-type.test.js @@ -577,6 +577,7 @@ test('any types are set on correct plugins', () => { --tw-text-opacity: var(--any-value); } .decoration-\[var\(--any-value\)\] { + -webkit-text-decoration-color: var(--any-value); text-decoration-color: var(--any-value); } .underline-offset-\[var\(--any-value\)\] { @@ -672,6 +673,10 @@ test('any types are set on correct plugins', () => { } .backdrop-blur-\[var\(--any-value\)\] { --tw-backdrop-blur: blur(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -679,6 +684,10 @@ test('any types are set on correct plugins', () => { } .backdrop-brightness-\[var\(--any-value\)\] { --tw-backdrop-brightness: brightness(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -686,6 +695,10 @@ test('any types are set on correct plugins', () => { } .backdrop-contrast-\[var\(--any-value\)\] { --tw-backdrop-contrast: contrast(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -693,6 +706,10 @@ test('any types are set on correct plugins', () => { } .backdrop-grayscale-\[var\(--any-value\)\] { --tw-backdrop-grayscale: grayscale(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -700,6 +717,10 @@ test('any types are set on correct plugins', () => { } .backdrop-hue-rotate-\[var\(--any-value\)\] { --tw-backdrop-hue-rotate: hue-rotate(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -707,6 +728,10 @@ test('any types are set on correct plugins', () => { } .backdrop-invert-\[var\(--any-value\)\] { --tw-backdrop-invert: invert(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -714,6 +739,10 @@ test('any types are set on correct plugins', () => { } .backdrop-opacity-\[var\(--any-value\)\] { --tw-backdrop-opacity: opacity(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -721,6 +750,10 @@ test('any types are set on correct plugins', () => { } .backdrop-saturate-\[var\(--any-value\)\] { --tw-backdrop-saturate: saturate(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) @@ -728,6 +761,10 @@ test('any types are set on correct plugins', () => { } .backdrop-sepia-\[var\(--any-value\)\] { --tw-backdrop-sepia: sepia(var(--any-value)); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) diff --git a/tests/apply.test.js b/tests/apply.test.js index e7627fb13..e0c324bf9 100644 --- a/tests/apply.test.js +++ b/tests/apply.test.js @@ -181,12 +181,12 @@ test('@apply', () => { .variants:focus { font-weight: 500; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .variants { font-weight: 300; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .variants:focus { font-weight: 900; } @@ -197,12 +197,12 @@ test('@apply', () => { .only-variants:focus { font-weight: 500; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .only-variants { font-weight: 300; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .only-variants:focus { font-weight: 900; } @@ -210,7 +210,7 @@ test('@apply', () => { .group:hover .apply-group-variant { text-align: center; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .group:hover .apply-group-variant { text-align: left; } @@ -221,7 +221,7 @@ test('@apply', () => { :is(.dark .apply-dark-variant:hover) { text-align: right; } - @media (width >= 1024px) { + @media (min-width: 1024px) { :is(.dark .apply-dark-variant) { text-align: left; } @@ -230,12 +230,12 @@ test('@apply', () => { .apply-custom-utility:hover { custom: stuff; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .apply-custom-utility { custom: stuff; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .apply-custom-utility:focus { custom: stuff; } @@ -255,7 +255,7 @@ test('@apply', () => { .selectors-variants:active { text-align: right; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .multiple-variants:focus, .selectors-variants:focus { text-align: left; @@ -265,7 +265,7 @@ test('@apply', () => { .group:hover .selectors-group { text-align: center; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .group:hover .multiple-group, .group:hover .selectors-group { text-align: left; @@ -321,12 +321,12 @@ test('@apply', () => { .recursive-apply-a { font-weight: 900; } - @media (width >= 640px) { + @media (min-width: 640px) { .recursive-apply-a { font-weight: 100; } } - @media (width >= 640px) { + @media (min-width: 640px) { .recursive-apply-b { font-weight: 100; } @@ -334,17 +334,17 @@ test('@apply', () => { .recursive-apply-b { font-weight: 600; } - @media (width >= 768px) { + @media (min-width: 768px) { .recursive-apply-b { font-weight: 200; } } - @media (width >= 640px) { + @media (min-width: 640px) { .recursive-apply-c { font-weight: 100; } } - @media (width >= 768px) { + @media (min-width: 768px) { .recursive-apply-c { font-weight: 200; } @@ -352,7 +352,7 @@ test('@apply', () => { .recursive-apply-c { font-weight: 700; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .recursive-apply-c { font-weight: 300; } @@ -369,13 +369,13 @@ test('@apply', () => { padding-left: 0.5rem; padding-right: 0.5rem; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .add-sibling-properties { padding-left: 2.5rem; padding-right: 2.5rem; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .add-sibling-properties:focus { padding-left: 0.25rem; padding-right: 0.25rem; @@ -390,13 +390,13 @@ test('@apply', () => { font-size: 1.5rem; line-height: 2rem; } - @media (width >= 640px) { + @media (min-width: 640px) { h1 { font-size: 1.875rem; line-height: 2.25rem; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { h1 { font-size: 1.5rem; line-height: 2rem; @@ -406,13 +406,13 @@ test('@apply', () => { font-size: 1.5rem; line-height: 2rem; } - @media (width >= 1024px) { + @media (min-width: 1024px) { h2 { font-size: 1.5rem; line-height: 2rem; } } - @media (width >= 640px) { + @media (min-width: 640px) { h2 { font-size: 1.5rem; line-height: 2rem; @@ -701,27 +701,27 @@ test('@applying classes from outside a @layer respects the source order', async .container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -1467,13 +1467,13 @@ describe('multiple instances', () => { font-size: 1.25rem; line-height: 1.75rem; } - @media (width >= 1024px) { + @media (min-width: 1024px) { h2 { font-size: 1.875rem; line-height: 2.25rem; } } - @media (width >= 640px) { + @media (min-width: 640px) { h2 { font-size: 1.5rem; line-height: 2rem; @@ -2021,18 +2021,27 @@ it('pseudo elements inside apply are moved outside of :is() or :has()', () => { :is([dir='rtl'] :is(.dark .baz:hover)):before { background-color: #000; } + :-webkit-any([dir='rtl'] :-webkit-any(.dark .qux))::-webkit-file-upload-button:hover { + background-color: #000; + } :is([dir='rtl'] :is(.dark .qux))::file-selector-button:hover { background-color: #000; } :is([dir='rtl'] :is(.dark .steve):hover):before { background-color: #000; } + :-webkit-any([dir='rtl'] :-webkit-any(.dark .bob))::-webkit-file-upload-button:hover { + background-color: #000; + } :is([dir='rtl'] :is(.dark .bob))::file-selector-button:hover { background-color: #000; } :has([dir='rtl'] .foo:hover):before { background-color: #000; } + :has([dir='rtl'] .bar)::-webkit-file-upload-button:hover { + background-color: #000; + } :has([dir='rtl'] .bar)::file-selector-button:hover { background-color: #000; } diff --git a/tests/arbitrary-properties.test.js b/tests/arbitrary-properties.test.js index c9ae197b9..17f0bcf1f 100644 --- a/tests/arbitrary-properties.test.js +++ b/tests/arbitrary-properties.test.js @@ -75,7 +75,7 @@ test('arbitrary properties with modifiers', () => { expect(result.css).toMatchFormattedCss(css` ${defaults} @media (prefers-color-scheme: dark) { - @media (width >= 1024px) { + @media (min-width: 1024px) { .dark\:lg\:hover\:\[paint-order\:markers\]:hover { paint-order: markers; } diff --git a/tests/arbitrary-values.test.css b/tests/arbitrary-values.test.css index 3b70e9363..ca434ed13 100644 --- a/tests/arbitrary-values.test.css +++ b/tests/arbitrary-values.test.css @@ -134,13 +134,13 @@ min-height: var(--height); } .w-\[\'\)\(\)\'\] { - width: ')()'; + width: ")()"; } .w-\[\'\]\[\]\'\] { - width: '][]'; + width: "][]"; } .w-\[\'\}\{\}\'\] { - width: '}{}'; + width: "}{}"; } .w-\[\(\(\)\)\] { width: (()); @@ -176,10 +176,14 @@ width: var(--width, calc(100% + 1rem)); } .w-\[\{\{\}\}\] { - width: {{}} + width: { + { + } + } } .w-\[\{\}\] { - width: {} + width: { + } } .min-w-\[3\.23rem\] { min-width: 3.23rem; @@ -345,10 +349,10 @@ cursor: pointer; } .cursor-\[url\(\'\.\/path_to_hand\.cur\'\)_2_2\,pointer\] { - cursor: url('./path_to_hand.cur') 2 2, pointer; + cursor: url("./path_to_hand.cur") 2 2, pointer; } .cursor-\[url\(hand\.cur\)_2_2\,pointer\] { - cursor: url('hand.cur') 2 2, pointer; + cursor: url("hand.cur") 2 2, pointer; } .cursor-\[var\(--value\)\] { cursor: var(--value); @@ -406,13 +410,13 @@ scroll-padding-top: var(--scroll-padding); } .list-\[\'\\1f44d\'\] { - list-style-type: '👍'; + list-style-type: "👍"; } .list-\[var\(--value\)\] { list-style-type: var(--value); } .list-image-\[url\(\.\/my-image\.png\)\] { - list-style-image: url('./my-image.png'); + list-style-image: url("./my-image.png"); } .list-image-\[var\(--value\)\] { list-style-image: var(--value); @@ -685,7 +689,7 @@ background-image: repeating-conic-gradient(#f8f9fa 0% 25%, #fff 0% 50%); } .bg-\[url\(\'\/path-to-image\.png\'\)\] { - background-image: url('/path-to-image.png'); + background-image: url("/path-to-image.png"); } .bg-\[url\:var\(--url\)\] { background-image: var(--url); @@ -735,7 +739,7 @@ fill: #da5b66; } .fill-\[url\(\#icon-gradient\)\] { - fill: url('#icon-gradient'); + fill: url("#icon-gradient"); } .fill-\[var\(--value\)\] { fill: var(--value); @@ -747,7 +751,7 @@ stroke: var(--value); } .stroke-\[url\(\#icon-gradient\)\] { - stroke: url('#icon-gradient'); + stroke: url("#icon-gradient"); } .stroke-\[20px\] { stroke-width: 20px; @@ -809,7 +813,7 @@ font-family: Some Font, sans-serif; } .font-\[\'Some_Font\'\,var\(--other-font\)\] { - font-family: 'Some Font', var(--other-font); + font-family: "Some Font", var(--other-font); } .font-\[Georgia\,serif\] { font-family: Georgia, serif; @@ -876,6 +880,7 @@ text-decoration-color: #000; } .decoration-\[color\:var\(--color\)\] { + -webkit-text-decoration-color: var(--color); text-decoration-color: var(--color); } .decoration-\[rgb\(123\,123\,123\)\], @@ -1026,54 +1031,90 @@ } .backdrop-blur-\[11px\] { --tw-backdrop-blur: blur(11px); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-brightness-\[1\.23\] { --tw-backdrop-brightness: brightness(1.23); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-contrast-\[0\.87\] { --tw-backdrop-contrast: contrast(0.87); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-grayscale-\[0\.42\] { --tw-backdrop-grayscale: grayscale(0.42); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-hue-rotate-\[1\.57rad\] { --tw-backdrop-hue-rotate: hue-rotate(89.9544deg); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-invert-\[0\.66\] { --tw-backdrop-invert: invert(0.66); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-opacity-\[22\%\] { --tw-backdrop-opacity: opacity(22%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-saturate-\[144\%\] { --tw-backdrop-saturate: saturate(144%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-sepia-\[0\.38\] { --tw-backdrop-sepia: sepia(0.38); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); @@ -1099,19 +1140,20 @@ will-change: var(--will-change); } .content-\[\'\>\'\] { - --tw-content: '>'; + --tw-content: ">"; content: var(--tw-content); } .content-\[\'hello\'\] { - --tw-content: 'hello'; + --tw-content: "hello"; content: var(--tw-content); } .content-\[attr\(content-before\)\] { --tw-content: attr(content-before); content: var(--tw-content); } -@media (width >= 1024px) { +@media (min-width: 1024px) { .lg\:grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] { grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px; } } + diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index 3bb8133c8..ed8e9388c 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -65,7 +65,7 @@ test('arbitrary variants with modifiers', () => { expect(result.css).toMatchFormattedCss(css` ${defaults} @media (prefers-color-scheme: dark) { - @media (width >= 1024px) { + @media (min-width: 1024px) { .dark\:lg\:hover\:\[\&\>\*\]\:underline > :hover { text-decoration-line: underline; } @@ -121,7 +121,7 @@ test('arbitrary variants are sorted after other variants', () => { .underline { text-decoration-line: underline; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .lg\:underline { text-decoration-line: underline; } @@ -1190,7 +1190,7 @@ it('should output responsive variants + stacked variants in the right order', () return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 1280px) { + @media (min-width: 1280px) { .xl\:p-1 { padding: 0.25rem; } @@ -1201,7 +1201,7 @@ it('should output responsive variants + stacked variants in the right order', () .\[\&_ul\]\:flex-col ul { flex-direction: column; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:\[\&_ul\]\:flex-row ul { flex-direction: row; } diff --git a/tests/basic-usage.test.css b/tests/basic-usage.test.css index 6efad7540..24a414b45 100644 --- a/tests/basic-usage.test.css +++ b/tests/basic-usage.test.css @@ -1,6 +1,103 @@ *, :before, -:after, +:after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} +::-webkit-backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} ::backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; @@ -53,27 +150,27 @@ .container { width: 100%; } -@media (width >= 640px) { +@media (min-width: 640px) { .container { max-width: 640px; } } -@media (width >= 768px) { +@media (min-width: 768px) { .container { max-width: 768px; } } -@media (width >= 1024px) { +@media (min-width: 1024px) { .container { max-width: 1024px; } } -@media (width >= 1280px) { +@media (min-width: 1280px) { .container { max-width: 1280px; } } -@media (width >= 1536px) { +@media (min-width: 1536px) { .container { max-width: 1536px; } @@ -427,6 +524,7 @@ touch-action: manipulation; } .select-none { + -webkit-user-select: none; user-select: none; } .resize-none { @@ -460,6 +558,7 @@ list-style-image: none; } .appearance-none { + -webkit-appearance: none; appearance: none; } .columns-1 { @@ -1020,69 +1119,110 @@ } .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-brightness-50 { --tw-backdrop-brightness: brightness(0.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-contrast-0 { --tw-backdrop-contrast: contrast(0); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-grayscale { --tw-backdrop-grayscale: grayscale(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-hue-rotate-90 { --tw-backdrop-hue-rotate: hue-rotate(90deg); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-invert { --tw-backdrop-invert: invert(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-opacity-75 { --tw-backdrop-opacity: opacity(0.75); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-saturate-150 { --tw-backdrop-saturate: saturate(1.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-sepia { --tw-backdrop-sepia: sepia(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter-none { + -webkit-backdrop-filter: none; backdrop-filter: none; } .transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; + opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } diff --git a/tests/blocklist.test.js b/tests/blocklist.test.js index 78958ca0c..e9915350f 100644 --- a/tests/blocklist.test.js +++ b/tests/blocklist.test.js @@ -27,7 +27,7 @@ it('can block classes matched literally', () => { .my-custom-class { color: red; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:hover\:text-sm:hover { font-size: 0.875rem; line-height: 1.25rem; diff --git a/tests/collapse-adjacent-rules.test.js b/tests/collapse-adjacent-rules.test.js index b0f668157..69c471686 100644 --- a/tests/collapse-adjacent-rules.test.js +++ b/tests/collapse-adjacent-rules.test.js @@ -106,7 +106,7 @@ test('collapse adjacent rules', () => { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .some-apply-thing { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); @@ -114,7 +114,7 @@ test('collapse adjacent rules', () => { } } @supports (foo: bar) { - @media (width >= 768px) { + @media (min-width: 768px) { .some-apply-thing { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); @@ -122,7 +122,7 @@ test('collapse adjacent rules', () => { } } } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:text-center { text-align: center; } @@ -130,7 +130,7 @@ test('collapse adjacent rules', () => { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:text-center { text-align: center; } @@ -138,7 +138,7 @@ test('collapse adjacent rules', () => { font-weight: 700; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .lg\:text-center { text-align: center; } diff --git a/tests/collapse-duplicate-declarations.test.js b/tests/collapse-duplicate-declarations.test.js index c75cc81dc..d36d2e83a 100644 --- a/tests/collapse-duplicate-declarations.test.js +++ b/tests/collapse-duplicate-declarations.test.js @@ -163,6 +163,7 @@ it('should work on a real world example', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` .h-available { + height: 100vh; height: -webkit-fill-available; } `) diff --git a/tests/containerPlugin.test.js b/tests/containerPlugin.test.js index 8db24fe8a..4b334e90c 100644 --- a/tests/containerPlugin.test.js +++ b/tests/containerPlugin.test.js @@ -8,27 +8,27 @@ test('options are not required', () => { .container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -52,12 +52,12 @@ test('screens can be passed explicitly', () => { .container { width: 100%; } - @media (width >= 400px) { + @media (min-width: 400px) { .container { max-width: 400px; } } - @media (width >= 500px) { + @media (min-width: 500px) { .container { max-width: 500px; } @@ -81,12 +81,12 @@ test('screens are ordered ascending by min-width', () => { .container { width: 100%; } - @media (width >= 400px) { + @media (min-width: 400px) { .container { max-width: 400px; } } - @media (width >= 500px) { + @media (min-width: 500px) { .container { max-width: 500px; } @@ -114,12 +114,12 @@ test('screens are deduplicated by min-width', () => { .container { width: 100%; } - @media (width >= 576px) { + @media (min-width: 576px) { .container { max-width: 576px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } @@ -145,27 +145,27 @@ test('the container can be centered by default', () => { margin-left: auto; margin-right: auto; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -191,27 +191,27 @@ test('horizontal padding can be included by default', () => { padding-left: 2rem; padding-right: 2rem; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -248,26 +248,26 @@ test('responsive horizontal padding can be included by default', () => { padding-left: 1rem; padding-right: 1rem; } - @media (width >= 576px) { + @media (min-width: 576px) { .container { max-width: 576px; padding-left: 2rem; padding-right: 2rem; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 992px) { + @media (min-width: 992px) { .container { max-width: 992px; padding-left: 4rem; padding-right: 4rem; } } - @media (width >= 1200px) { + @media (min-width: 1200px) { .container { max-width: 1200px; padding-left: 5rem; @@ -299,12 +299,12 @@ test('setting all options at once', () => { padding-left: 2rem; padding-right: 2rem; } - @media (width >= 400px) { + @media (min-width: 400px) { .container { max-width: 400px; } } - @media (width >= 500px) { + @media (min-width: 500px) { .container { max-width: 500px; } @@ -325,16 +325,16 @@ test('container can use variants', () => { return run('@tailwind components', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 1024px) { + @media (min-width: 1024px) { .lg\:hover\:container:hover { width: 100%; } - @media (width >= 400px) { + @media (min-width: 400px) { .lg\:hover\:container:hover { max-width: 400px; } } - @media (width >= 500px) { + @media (min-width: 500px) { .lg\:hover\:container:hover { max-width: 500px; } diff --git a/tests/custom-plugins.test.js b/tests/custom-plugins.test.js index 2c754d231..ac3547317 100644 --- a/tests/custom-plugins.test.js +++ b/tests/custom-plugins.test.js @@ -436,17 +436,17 @@ test('plugins can create components with media queries with object syntax', () = .custom-container { width: 100%; } - @media (width >= 100px) { + @media (min-width: 100px) { .custom-container { max-width: 100px; } } - @media (width >= 200px) { + @media (min-width: 200px) { .custom-container { max-width: 200px; } } - @media (width >= 300px) { + @media (min-width: 300px) { .custom-container { max-width: 300px; } @@ -497,7 +497,7 @@ test('media queries can be defined multiple times using objects-in-array syntax' .custom-container { width: 100%; } - @media (width >= 100px) { + @media (min-width: 100px) { .custom-container { max-width: 100px; } @@ -506,7 +506,7 @@ test('media queries can be defined multiple times using objects-in-array syntax' padding: 1rem 0.5rem; display: block; } - @media (width >= 100px) { + @media (min-width: 100px) { .btn { display: inline-block; } @@ -557,7 +557,7 @@ test('plugins can create nested rules', () => { .btn-blue:hover { background-color: #00008b; } - @media (width >= 500px) { + @media (min-width: 500px) { .btn-blue:hover { background-color: orange; } @@ -634,22 +634,22 @@ test('plugins can access the current config', () => { .custom-container { width: 100%; } - @media (width >= 576px) { + @media (min-width: 576px) { .custom-container { max-width: 576px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .custom-container { max-width: 768px; } } - @media (width >= 992px) { + @media (min-width: 992px) { .custom-container { max-width: 992px; } } - @media (width >= 1200px) { + @media (min-width: 1200px) { .custom-container { max-width: 1200px; } @@ -1254,7 +1254,7 @@ test('plugins can be created using the `createPlugin` function', () => { .hover\:test-sm:hover { test-property: 1rem; } - @media (width >= 400px) { + @media (min-width: 400px) { .sm\:test-sm { test-property: 1rem; } @@ -1319,7 +1319,7 @@ test('plugins with extra options can be created using the `createPlugin.withOpti .hover\:banana-sm:hover { test-property: 1rem; } - @media (width >= 400px) { + @media (min-width: 400px) { .sm\:banana-sm { test-property: 1rem; } @@ -1356,7 +1356,7 @@ test('plugins should cache correctly', () => { .banana { position: absolute; } - @media (width >= 400px) { + @media (min-width: 400px) { .sm\:banana { position: absolute; } @@ -1367,7 +1367,7 @@ test('plugins should cache correctly', () => { .apple { position: absolute; } - @media (width >= 400px) { + @media (min-width: 400px) { .sm\:apple { position: absolute; } @@ -1436,7 +1436,7 @@ test('plugins created using `createPlugin.withOptions` do not need to be invoked .hover\:banana-sm:hover { test-property: 1rem; } - @media (width >= 400px) { + @media (min-width: 400px) { .sm\:banana-sm { test-property: 1rem; } @@ -1493,7 +1493,7 @@ test('the configFunction parameter is optional when using the `createPlugin.with .hover\:banana-sm:hover { test-property: 1px; } - @media (width >= 400px) { + @media (min-width: 400px) { .sm\:banana-sm { test-property: 1px; } @@ -1534,7 +1534,7 @@ test('keyframes are not escaped', () => { .foo-\[abc\] { animation: 1s infinite abc; } - @media (width >= 768px) { + @media (min-width: 768px) { @keyframes def { 25.001% { color: #000; diff --git a/tests/custom-separator.test.js b/tests/custom-separator.test.js index 715238d64..3b1708dfb 100644 --- a/tests/custom-separator.test.js +++ b/tests/custom-separator.test.js @@ -33,7 +33,7 @@ test('custom separator', () => { :is(.dark .dark_focus_text-left:focus) { text-align: left; } - @media (width >= 768px) { + @media (min-width: 768px) { .md_hover_text-right:hover { text-align: right; } diff --git a/tests/customConfig.test.js b/tests/customConfig.test.js index e6c6f79ca..b8f459144 100644 --- a/tests/customConfig.test.js +++ b/tests/customConfig.test.js @@ -12,7 +12,7 @@ test('it uses the values from the custom config file', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } @@ -33,7 +33,7 @@ test('custom config can be passed as an object', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } @@ -49,7 +49,7 @@ test('custom config path can be passed using `config` property in an object', () return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } @@ -72,7 +72,7 @@ test('custom config can be passed under the `config` property', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } @@ -97,7 +97,7 @@ test('tailwind.config.cjs is picked up by default', () => { return run('@tailwind utilities').then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } @@ -123,7 +123,7 @@ test('tailwind.config.js is picked up by default', () => { return run('@tailwind utilities').then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } @@ -149,7 +149,7 @@ test('tailwind.config.cjs is picked up by default when passing an empty object', return run('@tailwind utilities', {}).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } @@ -175,7 +175,7 @@ test('tailwind.config.js is picked up by default when passing an empty object', return run('@tailwind utilities', {}).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 400px) { + @media (min-width: 400px) { .mobile\:font-bold { font-weight: 700; } diff --git a/tests/detect-nesting.test.js b/tests/detect-nesting.test.js index 555a80129..08eeacf98 100644 --- a/tests/detect-nesting.test.js +++ b/tests/detect-nesting.test.js @@ -88,7 +88,7 @@ it('should not warn when nesting a single rule inside a media query', () => { let input = css` @tailwind utilities; - @media (width >= 768px) { + @media (min-width: 768px) { .nested { } } diff --git a/tests/getVariants.test.js b/tests/getVariants.test.js index af34fd0e3..114d80824 100644 --- a/tests/getVariants.test.js +++ b/tests/getVariants.test.js @@ -86,7 +86,7 @@ it('should provide selectors for custom plugins that do a combination of paralle return [ ` @supports (foo: ${modifier}) { - @media (width <= 400px) { + @media (max-width: 400px) { &:hover } } @@ -103,7 +103,7 @@ it('should provide selectors for custom plugins that do a combination of paralle let variant = variants.find((v) => v.name === 'foo') expect(variant.selectors({ modifier: 'bar', value: 'baz' })).toEqual([ - '@supports (foo: bar) { @media (width <= 400px) { &:hover } }', + '@supports (foo: bar) { @media (max-width: 400px) { &:hover } }', '.bar\\/baz &:focus', ]) }) diff --git a/tests/import-syntax.test.js b/tests/import-syntax.test.js index a089cb955..99f5163f7 100644 --- a/tests/import-syntax.test.js +++ b/tests/import-syntax.test.js @@ -40,27 +40,27 @@ test('using @import instead of @tailwind', () => { .container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -72,7 +72,7 @@ test('using @import instead of @tailwind', () => { --tw-bg-opacity: 1; background-color: rgb(0 0 0 / var(--tw-bg-opacity)); } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:hover\:text-center:hover { text-align: center; } diff --git a/tests/important-boolean.test.js b/tests/important-boolean.test.js index de1eb3e3e..d66f21edc 100644 --- a/tests/important-boolean.test.js +++ b/tests/important-boolean.test.js @@ -80,27 +80,27 @@ test('important boolean', () => { .container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -148,7 +148,7 @@ test('important boolean', () => { :is(.dark .dark\:focus\:text-left:focus) { text-align: left !important; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:hover\:text-right:hover { text-align: right !important; } diff --git a/tests/important-modifier-prefix.test.js b/tests/important-modifier-prefix.test.js index 370c09dc2..2c6a8bb62 100644 --- a/tests/important-modifier-prefix.test.js +++ b/tests/important-modifier-prefix.test.js @@ -31,27 +31,27 @@ test('important modifier with prefix', () => { .\!tw-container { width: 100% !important; } - @media (width >= 640px) { + @media (min-width: 640px) { .\!tw-container { max-width: 640px !important; } } - @media (width >= 768px) { + @media (min-width: 768px) { .\!tw-container { max-width: 768px !important; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .\!tw-container { max-width: 1024px !important; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .\!tw-container { max-width: 1280px !important; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .\!tw-container { max-width: 1536px !important; } @@ -62,12 +62,12 @@ test('important modifier with prefix', () => { .hover\:\!tw-text-center:hover { text-align: center !important; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .lg\:\!tw-opacity-50 { opacity: 0.5 !important; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .xl\:focus\:disabled\:\!tw-float-right:disabled:focus { float: right !important; } diff --git a/tests/important-modifier.test.js b/tests/important-modifier.test.js index 44b07fbfd..fe4e14b33 100644 --- a/tests/important-modifier.test.js +++ b/tests/important-modifier.test.js @@ -53,27 +53,27 @@ test('important modifier', () => { .\!container { width: 100% !important; } - @media (width >= 640px) { + @media (min-width: 640px) { .\!container { max-width: 640px !important; } } - @media (width >= 768px) { + @media (min-width: 768px) { .\!container { max-width: 768px !important; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .\!container { max-width: 1024px !important; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .\!container { max-width: 1280px !important; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .\!container { max-width: 1536px !important; } @@ -94,12 +94,12 @@ test('important modifier', () => { .hover\:\!text-center:hover { text-align: center !important; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .lg\:\!opacity-50 { opacity: 0.5 !important; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .xl\:focus\:disabled\:\!float-right:disabled:focus { float: right !important; } diff --git a/tests/important-selector.test.js b/tests/important-selector.test.js index b9dc92b3a..1ec20922c 100644 --- a/tests/important-selector.test.js +++ b/tests/important-selector.test.js @@ -78,27 +78,27 @@ test('important selector', () => { .container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -150,11 +150,18 @@ test('important selector', () => { #app :is(.dark .dark\:focus\:text-left:focus) { text-align: left; } - @media (width >= 768px) { + @media (min-width: 768px) { #app .md\:hover\:text-right:hover { text-align: right; } } + #app + :-webkit-any( + [dir='rtl'] + :-webkit-any(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) + )::-webkit-file-upload-button:hover { + background-color: #000; + } #app :is( [dir='rtl'] :is(.dark .hover\:\[\&\:\:file-selector-button\]\:rtl\:dark\:bg-black\/100) @@ -165,7 +172,7 @@ test('important selector', () => { }) }) -test('pseudo-elements are appended after the `:is()`', () => { +test('pseudo-elements are appended after the `:-webkit-any()`', () => { let config = { important: '#app', darkMode: 'class', diff --git a/tests/kitchen-sink.test.js b/tests/kitchen-sink.test.js index 2763db668..b025f8625 100644 --- a/tests/kitchen-sink.test.js +++ b/tests/kitchen-sink.test.js @@ -243,7 +243,7 @@ test('it works', () => { Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .screen-test { color: purple; } @@ -261,7 +261,7 @@ test('it works', () => { .apply-test:hover:focus { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .apply-test { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); @@ -274,27 +274,27 @@ test('it works', () => { .apply-components { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .apply-components { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .apply-components { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .apply-components { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .apply-components { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .apply-components { max-width: 1536px; } @@ -311,7 +311,7 @@ test('it works', () => { .apply-with-existing:hover { font-weight: 400; } - @media (width >= 640px) { + @media (min-width: 640px) { .apply-with-existing:hover { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); @@ -344,7 +344,7 @@ test('it works', () => { --tw-bg-opacity: 1; background-color: rgb(34 197 94 / var(--tw-bg-opacity)); } - @media (width >= 640px) { + @media (min-width: 640px) { @media (prefers-reduced-motion: no-preference) { .group:active .crazy-example:focus { opacity: 0.1; @@ -365,27 +365,27 @@ test('it works', () => { .container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .container { max-width: 1536px; } @@ -401,11 +401,22 @@ test('it works', () => { } *, :before, - :after, + :after { + padding: 5px; + } + *, + :before, + :after { + padding: 5px; + } + ::-webkit-backdrop { + padding: 5px; + } ::backdrop { padding: 5px; } .foo .bg-black { + -webkit-appearance: none; appearance: none; } .inset-6 { @@ -573,93 +584,103 @@ test('it works', () => { } *, :before, - :after, + :after { + margin: 10px; + } + *, + :before, + :after { + margin: 10px; + } + ::-webkit-backdrop { + margin: 10px; + } ::backdrop { margin: 10px; } .hover\:container:hover { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .hover\:container:hover { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .hover\:container:hover { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .hover\:container:hover { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .hover\:container:hover { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .hover\:container:hover { max-width: 1536px; } } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .sm\:container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .sm\:container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .sm\:container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .sm\:container { max-width: 1536px; } } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .md\:container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .md\:container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .md\:container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .md\:container { max-width: 1536px; } @@ -724,7 +745,7 @@ test('it works', () => { @media (prefers-reduced-motion: no-preference) { .motion-safe\:transition { transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; + stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } @@ -735,7 +756,7 @@ test('it works', () => { @media (prefers-reduced-motion: reduce) { .motion-reduce\:transition { transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; + stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } @@ -743,7 +764,7 @@ test('it works', () => { :is(.dark .dark\:custom-util) { background: #abcdef; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:text-center { text-align: center; } @@ -761,7 +782,7 @@ test('it works', () => { } } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:text-center { text-align: center; } @@ -783,7 +804,8 @@ test('it works', () => { @media (prefers-reduced-motion: no-preference) { .md\:motion-safe\:hover\:transition:hover { transition-property: color, background-color, border-color, text-decoration-color, fill, - stroke, opacity, box-shadow, transform, filter, backdrop-filter; + stroke, opacity, box-shadow, transform, filter, -webkit-backdrop-filter, + backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } @@ -791,18 +813,18 @@ test('it works', () => { background: #abcdef !important; } } - @media (width >= 640px) { + @media (min-width: 640px) { .md\:sm\:text-center { text-align: center; } } } - @media (width >= 1280px) and (width <= 1535px) { + @media (min-width: 1280px) and (max-width: 1535px) { .range\:text-right { text-align: right; } } - @media (width >= 640px) and (width <= 767px), (width <= 868px) { + @media (min-width: 640px) and (max-width: 767px), (max-width: 868px) { .multi\:text-left { text-align: left; } diff --git a/tests/layer-at-rules.test.js b/tests/layer-at-rules.test.js index 1c4604835..ac1b11bd5 100644 --- a/tests/layer-at-rules.test.js +++ b/tests/layer-at-rules.test.js @@ -309,7 +309,7 @@ it('should keep `@supports` rules inside `@layer`s', () => { .test { --tw-test: 1; } - @supports (backdrop-filter: blur(1px)) { + @supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { .test { --tw-test: 0.9; } diff --git a/tests/match-variants.test.js b/tests/match-variants.test.js index 0c9034eee..2923b10c0 100644 --- a/tests/match-variants.test.js +++ b/tests/match-variants.test.js @@ -244,12 +244,12 @@ it('should be possible to sort variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 500px) { + @media (min-width: 500px) { .testmin-\[500px\]\:underline { text-decoration-line: underline; } } - @media (width >= 700px) { + @media (min-width: 700px) { .testmin-\[700px\]\:italic { font-style: italic; } @@ -290,17 +290,17 @@ it('should be possible to compare arbitrary variants and hardcoded variants', () return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 500px) { + @media (min-width: 500px) { .testmin-\[500px\]\:italic { font-style: italic; } } - @media (width >= 600px) { + @media (min-width: 600px) { .testmin-example\:italic { font-style: italic; } } - @media (width >= 700px) { + @media (min-width: 700px) { .testmin-\[700px\]\:italic { font-style: italic; } @@ -351,25 +351,25 @@ it('should be possible to sort stacked arbitrary variants correctly', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 100px) { - @media (width <= 400px) { + @media (min-width: 100px) { + @media (max-width: 400px) { .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (width <= 350px) { + @media (max-width: 350px) { .testmin-\[100px\]\:testmax-\[350px\]\:underline { text-decoration-line: underline; } } - @media (width <= 300px) { + @media (max-width: 300px) { .testmin-\[100px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } } } - @media (width >= 150px) { - @media (width <= 400px) { + @media (min-width: 150px) { + @media (max-width: 400px) { .testmin-\[150px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } @@ -415,8 +415,8 @@ it('should maintain sort from other variants, if sort functions of arbitrary var return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 100px) { - @media (width <= 200px) { + @media (min-width: 100px) { + @media (max-width: 200px) { .testmin-\[100px\]\:testmax-\[200px\]\:hover\:underline:hover, .testmin-\[100px\]\:testmax-\[200px\]\:focus\:underline:focus { text-decoration-line: underline; @@ -464,25 +464,25 @@ it('should sort arbitrary variants left to right (1)', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 100px) { - @media (width <= 400px) { + @media (min-width: 100px) { + @media (max-width: 400px) { .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (width <= 300px) { + @media (max-width: 300px) { .testmin-\[100px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } } } - @media (width >= 200px) { - @media (width <= 400px) { + @media (min-width: 200px) { + @media (max-width: 400px) { .testmin-\[200px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (width <= 300px) { + @media (max-width: 300px) { .testmin-\[200px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } @@ -529,26 +529,26 @@ it('should sort arbitrary variants left to right (2)', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width <= 400px) { - @media (width >= 100px) { + @media (max-width: 400px) { + @media (min-width: 100px) { .testmax-\[400px\]\:testmin-\[100px\]\:underline { text-decoration-line: underline; } } - @media (width >= 200px) { + @media (min-width: 200px) { .testmax-\[400px\]\:testmin-\[200px\]\:underline { text-decoration-line: underline; } } } - @media (width <= 300px) { - @media (width >= 100px) { + @media (max-width: 300px) { + @media (min-width: 100px) { .testmax-\[300px\]\:testmin-\[100px\]\:underline { text-decoration-line: underline; } } - @media (width >= 200px) { + @media (min-width: 200px) { .testmax-\[300px\]\:testmin-\[200px\]\:underline { text-decoration-line: underline; } @@ -603,28 +603,28 @@ it('should guarantee that we are not passing values from other variants to the w return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 100px) { - @media (width <= 400px) { + @media (min-width: 100px) { + @media (max-width: 400px) { .testmin-\[100px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (width <= 300px) { + @media (max-width: 300px) { .testmin-\[100px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } } } - @media (width >= 200px) { - @media (width <= 400px) { + @media (min-width: 200px) { + @media (max-width: 400px) { .testmin-\[200px\]\:testmax-\[400px\]\:underline { text-decoration-line: underline; } } - @media (width <= 300px) { + @media (max-width: 300px) { .testmin-\[200px\]\:testmax-\[300px\]\:underline { text-decoration-line: underline; } diff --git a/tests/min-max-screen-variants.test.js b/tests/min-max-screen-variants.test.js index b6ea5d254..beab47ac0 100644 --- a/tests/min-max-screen-variants.test.js +++ b/tests/min-max-screen-variants.test.js @@ -34,32 +34,32 @@ it('sorts min and max correctly relative to screens and each other', async () => .font-bold { font-weight: 700; } - @media (width <= 800px) { + @media (max-width: 800px) { .max-\[800px\]\:font-bold { font-weight: 700; } } - @media (width <= 700px) { + @media (max-width: 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 700px) { + @media (min-width: 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } } - @media (width >= 800px) { + @media (min-width: 800px) { .min-\[800px\]\:font-bold { font-weight: 700; } @@ -95,12 +95,12 @@ it('works when using min variants screens config is empty and variants all use t .font-bold { font-weight: 700; } - @media (width >= 700px) { + @media (min-width: 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } - @media (width >= 800px) { + @media (min-width: 800px) { .min-\[800px\]\:font-bold { font-weight: 700; } @@ -136,12 +136,12 @@ it('works when using max variants screens config is empty and variants all use t .font-bold { font-weight: 700; } - @media (width <= 800px) { + @media (max-width: 800px) { .max-\[800px\]\:font-bold { font-weight: 700; } } - @media (width <= 700px) { + @media (max-width: 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } @@ -176,32 +176,32 @@ it('converts simple min-width screens for max variant', () => { .font-bold { font-weight: 700; } - @media not all and (width >= 1024px) { + @media not all and (min-width: 1024px) { .max-lg\:font-bold { font-weight: 700; } } - @media (width <= 700px) { + @media (max-width: 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } } - @media not all and (width >= 640px) { + @media not all and (min-width: 640px) { .max-sm\:font-bold { font-weight: 700; } } - @media (width <= 300px) { + @media (max-width: 300px) { .max-\[300px\]\:font-bold { font-weight: 700; } } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } @@ -236,22 +236,22 @@ it('does not have keyed screens for min variant', () => { .font-bold { font-weight: 700; } - @media (width >= 300px) { + @media (min-width: 300px) { .min-\[300px\]\:font-bold { font-weight: 700; } } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 700px) { + @media (min-width: 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } @@ -292,12 +292,12 @@ it('warns when using min variants with complex screen configs', async () => { .font-bold { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } @@ -336,12 +336,12 @@ it('warns when using min variants with simple configs containing mixed units', a .font-bold { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 48rem) { + @media (min-width: 48rem) { .md\:font-bold { font-weight: 700; } @@ -380,12 +380,12 @@ it('warns when using min variants with mixed units (with screens config)', async .font-bold { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } @@ -422,7 +422,7 @@ it('warns when using min variants with mixed units (with no screens config)', as .font-bold { font-weight: 700; } - @media (width >= 700px) { + @media (min-width: 700px) { .min-\[700px\]\:font-bold { font-weight: 700; } @@ -464,12 +464,12 @@ it('warns when using max variants with complex screen configs', async () => { .font-bold { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } @@ -508,12 +508,12 @@ it('warns when using max variants with simple configs containing mixed units', a .font-bold { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 48rem) { + @media (min-width: 48rem) { .md\:font-bold { font-weight: 700; } @@ -552,12 +552,12 @@ it('warns when using max variants with mixed units (with screens config)', async .font-bold { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } @@ -594,7 +594,7 @@ it('warns when using max variants with mixed units (with no screens config)', as .font-bold { font-weight: 700; } - @media (width <= 700px) { + @media (max-width: 700px) { .max-\[700px\]\:font-bold { font-weight: 700; } @@ -631,7 +631,7 @@ it('warns when using min and max variants with mixed units (with no screens conf .font-bold { font-weight: 700; } - @media (width <= 700rem) { + @media (max-width: 700rem) { .max-\[700rem\]\:font-bold { font-weight: 700; } diff --git a/tests/modify-selectors.test.js b/tests/modify-selectors.test.js index aef52b8a4..e6ce3cf14 100644 --- a/tests/modify-selectors.test.js +++ b/tests/modify-selectors.test.js @@ -69,7 +69,7 @@ test('modify selectors', () => { .foo .foo\:visited\:markdown:visited > p { margin-top: 12px; } - @media (width >= 1024px) { + @media (min-width: 1024px) { .foo .lg\:foo\:disabled\:markdown:disabled > p { margin-top: 12px; } @@ -78,12 +78,12 @@ test('modify selectors', () => { .foo .foo\:hover\:font-bold:hover { font-weight: 700; } - @media (width >= 640px) { + @media (min-width: 640px) { .foo .sm\:foo\:font-bold { font-weight: 700; } } - @media (width >= 768px) { + @media (min-width: 768px) { .foo .md\:foo\:focus\:font-bold:focus { font-weight: 700; } diff --git a/tests/oxide-svelte.test.css b/tests/oxide-svelte.test.css index d4889d746..ef36fec77 100644 --- a/tests/oxide-svelte.test.css +++ b/tests/oxide-svelte.test.css @@ -102,7 +102,7 @@ --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } -@media (width >= 1024px) { +@media (min-width: 1024px) { .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); diff --git a/tests/parseObjectStyles.test.js b/tests/parseObjectStyles.test.js index 1771b58b7..c1a602038 100644 --- a/tests/parseObjectStyles.test.js +++ b/tests/parseObjectStyles.test.js @@ -82,7 +82,7 @@ test('it parses nested pseudo-selectors', () => { test('it parses top-level media queries', () => { let result = parseObjectStyles({ - '@media (width >= 200px)': { + '@media (min-width: 200px)': { '.foo': { backgroundColor: 'orange', }, @@ -90,7 +90,7 @@ test('it parses top-level media queries', () => { }) expect(toCss(result)).toMatchFormattedCss(css` - @media (width >= 200px) { + @media (min-width: 200px) { .foo { background-color: orange; } @@ -104,7 +104,7 @@ test('it parses nested media queries', () => { backgroundColor: 'red', color: 'white', padding: '1rem', - '@media (width >= 200px)': { + '@media (min-width: 200px)': { backgroundColor: 'orange', }, }, @@ -116,7 +116,7 @@ test('it parses nested media queries', () => { color: white; padding: 1rem; } - @media (width >= 200px) { + @media (min-width: 200px) { .foo { background-color: orange; } @@ -157,7 +157,7 @@ test('it parses pseudo-selectors in nested media queries', () => { color: 'white', padding: '1rem', '&:hover': { - '@media (width >= 200px)': { + '@media (min-width: 200px)': { backgroundColor: 'orange', }, }, @@ -170,7 +170,7 @@ test('it parses pseudo-selectors in nested media queries', () => { color: white; padding: 1rem; } - @media (width >= 200px) { + @media (min-width: 200px) { .foo:hover { background-color: orange; } @@ -232,7 +232,7 @@ test('it parses nested multi-class selectors in media queries', () => { backgroundColor: 'red', color: 'white', padding: '1rem', - '@media (width >= 200px)': { + '@media (min-width: 200px)': { '&.bar': { backgroundColor: 'orange', }, @@ -246,7 +246,7 @@ test('it parses nested multi-class selectors in media queries', () => { color: white; padding: 1rem; } - @media (width >= 200px) { + @media (min-width: 200px) { .foo.bar { background-color: orange; } diff --git a/tests/plugins/fontSize.test.js b/tests/plugins/fontSize.test.js index 4b0099936..99f67eaf6 100644 --- a/tests/plugins/fontSize.test.js +++ b/tests/plugins/fontSize.test.js @@ -168,7 +168,7 @@ test('font-size utilities can include a line-height modifier', () => { font-size: 12px; line-height: 21px; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:text-\[19px\]\/8 { font-size: 19px; line-height: 32px; diff --git a/tests/prefix.test.js b/tests/prefix.test.js index 1306481e3..c9c0e5f25 100644 --- a/tests/prefix.test.js +++ b/tests/prefix.test.js @@ -94,27 +94,27 @@ test('prefix', () => { .tw-container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .tw-container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .tw-container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .tw-container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .tw-container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .tw-container { max-width: 1536px; } @@ -168,7 +168,7 @@ test('prefix', () => { :is(.tw-dark .dark\:focus\:tw-text-left:focus) { text-align: left; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:tw--ml-5 { margin-left: -1.25rem; } @@ -440,7 +440,7 @@ test('prefix with negative values and variants in the safelist', async () => { .hover\:tw--top-1:hover { top: -0.25rem; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:hover\:-tw-top-1:hover, .sm\:hover\:tw--top-1:hover { top: -0.25rem; diff --git a/tests/raw-content.test.css b/tests/raw-content.test.css index f93deda00..cc43ad4c4 100644 --- a/tests/raw-content.test.css +++ b/tests/raw-content.test.css @@ -1,27 +1,27 @@ .container { width: 100%; } -@media (width >= 640px) { +@media (min-width: 640px) { .container { max-width: 640px; } } -@media (width >= 768px) { +@media (min-width: 768px) { .container { max-width: 768px; } } -@media (width >= 1024px) { +@media (min-width: 1024px) { .container { max-width: 1024px; } } -@media (width >= 1280px) { +@media (min-width: 1280px) { .container { max-width: 1280px; } } -@media (width >= 1536px) { +@media (min-width: 1536px) { .container { max-width: 1536px; } @@ -265,6 +265,7 @@ cursor: pointer; } .select-none { + -webkit-user-select: none; user-select: none; } .resize-none { @@ -277,6 +278,7 @@ list-style-type: disc; } .appearance-none { + -webkit-appearance: none; appearance: none; } .auto-cols-min { @@ -701,69 +703,110 @@ } .backdrop-blur-lg { --tw-backdrop-blur: blur(16px); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-brightness-50 { --tw-backdrop-brightness: brightness(0.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-contrast-0 { --tw-backdrop-contrast: contrast(0); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-grayscale { --tw-backdrop-grayscale: grayscale(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-hue-rotate-90 { --tw-backdrop-hue-rotate: hue-rotate(90deg); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-invert { --tw-backdrop-invert: invert(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-opacity-75 { --tw-backdrop-opacity: opacity(0.75); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-saturate-150 { --tw-backdrop-saturate: saturate(1.5); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-sepia { --tw-backdrop-sepia: sepia(100%); + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter { + -webkit-backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) + var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) + var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) + var(--tw-backdrop-sepia); backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia); } .backdrop-filter-none { + -webkit-backdrop-filter: none; backdrop-filter: none; } .transition { transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, - opacity, box-shadow, transform, filter, backdrop-filter; + opacity, box-shadow, transform, filter, -webkit-backdrop-filter, backdrop-filter; transition-duration: 0.15s; transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); } diff --git a/tests/resolve-defaults-at-rules.test.js b/tests/resolve-defaults-at-rules.test.js index 0ecb4cdc5..18424e712 100644 --- a/tests/resolve-defaults-at-rules.test.js +++ b/tests/resolve-defaults-at-rules.test.js @@ -16,7 +16,24 @@ test('basic utilities', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; @@ -66,7 +83,24 @@ test('with pseudo-class variants', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; @@ -114,7 +148,24 @@ test('with pseudo-element variants', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; @@ -158,7 +209,24 @@ test('with multi-class variants', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; @@ -202,7 +270,24 @@ test('with multi-class pseudo-element variants', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; @@ -252,7 +337,24 @@ test('with multi-class pseudo-element and pseudo-class variants', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; @@ -338,7 +440,24 @@ test('with apply', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; @@ -374,7 +493,7 @@ test('with apply', async () => { skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } - @media (width >= 768px) { + @media (min-width: 768px) { .media-queries { --tw-rotate: 45deg; transform: translate(var(--tw-translate-x), var(--tw-translate-y)) @@ -506,7 +625,7 @@ test('with borders', async () => { --tw-border-opacity: 1; border-color: rgb(239 68 68 / var(--tw-border-opacity)); } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:border-2 { border-width: 2px; } @@ -531,7 +650,26 @@ test('with shadows', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } + ::-webkit-backdrop { + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + } ::backdrop { --tw-ring-inset: ; --tw-ring-offset-width: 0px; @@ -559,7 +697,7 @@ test('with shadows', async () => { .ring-black\/25 { --tw-ring-color: #00000040; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:shadow-xl { --tw-shadow: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; --tw-shadow-colored: 0 20px 25px -5px var(--tw-shadow-color), @@ -588,7 +726,24 @@ test('when no utilities that need the defaults are used', async () => { expect(result.css).toMatchFormattedCss(css` *, :before, - :after, + :after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } + ::-webkit-backdrop { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + } ::backdrop { --tw-translate-x: 0; --tw-translate-y: 0; diff --git a/tests/responsive-and-variants-atrules.test.js b/tests/responsive-and-variants-atrules.test.js index 8eea80729..4d4a0f507 100644 --- a/tests/responsive-and-variants-atrules.test.js +++ b/tests/responsive-and-variants-atrules.test.js @@ -121,7 +121,7 @@ test('responsive and variants atrules', () => { .both-at-root { color: pink; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:focus\:responsive-in-components:focus { color: #00f; } diff --git a/tests/source-maps.test.js b/tests/source-maps.test.js index 88aa59ded..4cfcd62d8 100644 --- a/tests/source-maps.test.js +++ b/tests/source-maps.test.js @@ -109,179 +109,279 @@ test('preflight + base have source maps', async () => { "27:2-11 -> 27:2-11", "28:0 -> 28:0", "2:4 -> 30:0", - "31:2-35 -> 31:2-35", - "32:0 -> 32:0", - "2:4 -> 34:0", - "35:2-20 -> 35:2-20", - "36:2-22 -> 36:2-22", - "37:0 -> 37:0", - "2:4 -> 39:0", - "40:2-16 -> 40:2-16", - "41:2-26 -> 41:2-26", - "42:0 -> 42:0", - "2:4 -> 44:0", - "45:2-21 -> 45:2-21", - "46:0 -> 46:0", - "2:4 -> 48:0", - "49:2-109 -> 49:2-109", - "50:2-16 -> 50:2-16", - "51:0 -> 51:0", - "2:4 -> 53:0", - "54:2-16 -> 54:2-16", - "55:0 -> 55:0", - "2:4 -> 57:0", - "58:2-26 -> 58:2-26", - "59:2-16 -> 59:2-16", - "60:2-16 -> 60:2-16", - "61:2-20 -> 61:2-20", - "62:0 -> 62:0", - "2:4 -> 64:0", - "65:2-16 -> 65:2-16", - "66:0 -> 66:0", - "2:4 -> 68:0", - "69:2-12 -> 69:2-12", - "70:0 -> 70:0", - "2:4 -> 72:0", - "73:2-16 -> 73:2-16", - "74:2-23 -> 74:2-23", - "75:2-27 -> 75:2-27", - "76:0 -> 76:0", - "2:4 -> 78:0", - "79:2-32 -> 79:2-32", - "80:2-34 -> 80:2-34", - "81:2-22 -> 81:2-22", - "82:2-17 -> 82:2-17", + "31:2-43 -> 31:2-43", + "32:2-35 -> 32:2-35", + "33:0 -> 33:0", + "2:4 -> 35:0", + "36:2-20 -> 36:2-20", + "37:2-22 -> 37:2-22", + "38:0 -> 38:0", + "2:4 -> 40:0", + "41:2-16 -> 41:2-16", + "42:2-34 -> 42:2-34", + "43:2-26 -> 43:2-26", + "44:0 -> 44:0", + "2:4 -> 46:0", + "47:2-21 -> 47:2-21", + "48:0 -> 48:0", + "2:4 -> 50:0", + "51:2-109 -> 51:2-109", + "52:2-16 -> 52:2-16", + "53:0 -> 53:0", + "2:4 -> 55:0", + "56:2-16 -> 56:2-16", + "57:0 -> 57:0", + "2:4 -> 59:0", + "60:2-26 -> 60:2-26", + "61:2-16 -> 61:2-16", + "62:2-16 -> 62:2-16", + "63:2-20 -> 63:2-20", + "64:0 -> 64:0", + "2:4 -> 66:0", + "67:2-16 -> 67:2-16", + "68:0 -> 68:0", + "2:4 -> 70:0", + "71:2-12 -> 71:2-12", + "72:0 -> 72:0", + "2:4 -> 74:0", + "75:2-16 -> 75:2-16", + "76:2-23 -> 76:2-23", + "77:2-27 -> 77:2-27", + "78:0 -> 78:0", + "2:4 -> 80:0", + "81:2-32 -> 81:2-32", + "82:2-34 -> 82:2-34", "83:2-22 -> 83:2-22", - "84:2-22 -> 84:2-22", - "85:2-16 -> 85:2-16", - "86:2-11 -> 86:2-11", - "87:2-12 -> 87:2-12", - "88:0 -> 88:0", - "2:4 -> 90:0", - "91:2-22 -> 91:2-22", - "92:0 -> 92:0", - "2:4 -> 94:0", - "95:2-28 -> 95:2-28", - "96:2-25 -> 96:2-25", - "97:2-24 -> 97:2-24", - "98:0 -> 98:0", - "2:4 -> 100:0", - "101:2-15 -> 101:2-15", - "102:0 -> 102:0", - "2:4 -> 104:0", - "105:2-18 -> 105:2-18", - "106:0 -> 106:0", - "2:4 -> 108:0", - "109:2-26 -> 109:2-26", - "110:0 -> 110:0", - "2:4 -> 112:0", - "113:2-14 -> 113:2-14", - "114:0 -> 114:0", - "2:4 -> 116:0", - "117:2-31 -> 117:2-31", - "118:2-22 -> 118:2-22", - "119:0 -> 119:0", - "2:4 -> 121:0", - "122:2-26 -> 122:2-26", - "123:0 -> 123:0", - "2:4 -> 125:0", - "126:2-28 -> 126:2-28", - "127:2-15 -> 127:2-15", - "128:0 -> 128:0", - "2:4 -> 130:0", - "131:2-20 -> 131:2-20", - "132:0 -> 132:0", - "2:4 -> 134:0", - "135:2-11 -> 135:2-11", - "136:0 -> 136:0", - "2:4 -> 138:0", - "139:2-11 -> 139:2-11", - "140:2-12 -> 140:2-12", - "141:0 -> 141:0", - "2:4 -> 143:0", - "144:2-12 -> 144:2-12", - "145:0 -> 145:0", - "2:4 -> 147:0", - "148:2-11 -> 148:2-11", - "149:2-12 -> 149:2-12", - "150:2-18 -> 150:2-18", - "151:0 -> 151:0", - "2:4 -> 153:0", - "154:2-12 -> 154:2-12", - "155:0 -> 155:0", - "2:4 -> 157:0", - "158:2-18 -> 158:2-18", - "159:0 -> 159:0", - "2:4 -> 161:0", - "162:2-12 -> 162:2-12", - "163:2-16 -> 163:2-16", - "164:0 -> 164:0", - "2:4 -> 166:0", - "167:2-17 -> 167:2-17", - "168:0 -> 168:0", - "2:4 -> 170:0", - "171:2-17 -> 171:2-17", - "172:0 -> 172:0", - "2:4 -> 174:0", - "175:2-24 -> 175:2-24", - "176:2-16 -> 176:2-16", - "177:0 -> 177:0", - "2:4 -> 179:0", - "180:2-17 -> 180:2-17", - "181:2-14 -> 181:2-14", - "182:0 -> 182:0", - "2:4 -> 184:0", - "185:2-15 -> 185:2-15", - "186:0 -> 186:0", - "2:4 -> 188:0", - "189:2-26 -> 189:2-26", - "190:2-26 -> 190:2-26", - "191:2-21 -> 191:2-21", - "192:2-21 -> 192:2-21", - "193:2-16 -> 193:2-16", - "194:2-16 -> 194:2-16", + "84:2-17 -> 84:2-17", + "85:2-22 -> 85:2-22", + "86:2-22 -> 86:2-22", + "87:2-16 -> 87:2-16", + "88:2-11 -> 88:2-11", + "89:2-12 -> 89:2-12", + "90:0 -> 90:0", + "2:4 -> 92:0", + "93:2-22 -> 93:2-22", + "94:0 -> 94:0", + "2:4 -> 96:0", + "97:2-28 -> 97:2-28", + "98:2-25 -> 98:2-25", + "99:2-24 -> 99:2-24", + "100:0 -> 100:0", + "2:4 -> 102:0", + "103:2-15 -> 103:2-15", + "104:0 -> 104:0", + "2:4 -> 106:0", + "107:2-18 -> 107:2-18", + "108:0 -> 108:0", + "2:4 -> 110:0", + "111:2-26 -> 111:2-26", + "112:0 -> 112:0", + "2:4 -> 114:0", + "115:2-14 -> 115:2-14", + "116:0 -> 116:0", + "2:4 -> 118:0", + "119:2-31 -> 119:2-31", + "120:2-22 -> 120:2-22", + "121:0 -> 121:0", + "2:4 -> 123:0", + "124:2-26 -> 124:2-26", + "125:0 -> 125:0", + "2:4 -> 127:0", + "128:2-28 -> 128:2-28", + "129:2-15 -> 129:2-15", + "130:0 -> 130:0", + "2:4 -> 132:0", + "133:2-20 -> 133:2-20", + "134:0 -> 134:0", + "2:4 -> 136:0", + "137:2-11 -> 137:2-11", + "138:0 -> 138:0", + "2:4 -> 140:0", + "141:2-11 -> 141:2-11", + "142:2-12 -> 142:2-12", + "143:0 -> 143:0", + "2:4 -> 145:0", + "146:2-12 -> 146:2-12", + "147:0 -> 147:0", + "2:4 -> 149:0", + "150:2-11 -> 150:2-11", + "151:2-12 -> 151:2-12", + "152:2-18 -> 152:2-18", + "153:0 -> 153:0", + "2:4 -> 155:0", + "156:2-12 -> 156:2-12", + "157:0 -> 157:0", + "2:4 -> 159:0", + "160:2-18 -> 160:2-18", + "161:0 -> 161:0", + "2:4 -> 163:0", + "164:2-12 -> 164:2-12", + "165:2-16 -> 165:2-16", + "166:0 -> 166:0", + "2:4 -> 168:0", + "169:2-17 -> 169:2-17", + "170:0 -> 170:0", + "2:4 -> 172:0", + "173:2-17 -> 173:2-17", + "174:0 -> 174:0", + "2:4 -> 176:0", + "177:2-24 -> 177:2-24", + "178:2-16 -> 178:2-16", + "179:0 -> 179:0", + "2:4 -> 181:0", + "182:2-17 -> 182:2-17", + "183:2-14 -> 183:2-14", + "184:0 -> 184:0", + "2:4 -> 186:0", + "187:2-15 -> 187:2-15", + "188:0 -> 188:0", + "2:4 -> 190:0", + "191:2-26 -> 191:2-26", + "192:2-26 -> 192:2-26", + "193:2-21 -> 193:2-21", + "194:2-21 -> 194:2-21", "195:2-16 -> 195:2-16", - "196:2-17 -> 196:2-17", - "197:2-17 -> 197:2-17", - "198:2-14 -> 198:2-14", - "199:2-14 -> 199:2-14", - "200:2-19 -> 200:2-19", - "201:2-40 -> 201:2-40", - "202:2-31 -> 202:2-31", - "203:2-30 -> 203:2-30", - "204:2-29 -> 204:2-29", - "205:2-16 -> 205:2-16", - "206:2-21 -> 206:2-21", - "207:2-23 -> 207:2-23", - "208:2-24 -> 208:2-24", - "209:2-25 -> 209:2-25", - "210:2-19 -> 210:2-19", - "211:2-29 -> 211:2-29", - "212:2-30 -> 212:2-30", - "213:2-28 -> 213:2-28", - "214:2-36 -> 214:2-36", - "215:2-29 -> 215:2-29", - "216:2-24 -> 216:2-24", - "217:2-32 -> 217:2-32", - "218:2-13 -> 218:2-13", - "219:2-19 -> 219:2-19", - "220:2-17 -> 220:2-17", - "221:2-18 -> 221:2-18", - "222:2-19 -> 222:2-19", - "223:2-15 -> 223:2-15", - "224:2-17 -> 224:2-17", - "225:2-14 -> 225:2-14", - "226:2-20 -> 226:2-20", - "227:2-22 -> 227:2-22", - "228:2-28 -> 228:2-28", - "229:2-26 -> 229:2-26", - "230:2-27 -> 230:2-27", - "231:2-28 -> 231:2-28", - "232:2-24 -> 232:2-24", - "233:2-25 -> 233:2-25", - "234:2-26 -> 234:2-26", - "235:2-23 -> 235:2-23", - "236:0 -> 236:0", + "196:2-16 -> 196:2-16", + "197:2-16 -> 197:2-16", + "198:2-17 -> 198:2-17", + "199:2-17 -> 199:2-17", + "200:2-14 -> 200:2-14", + "201:2-14 -> 201:2-14", + "202:2-19 -> 202:2-19", + "203:2-40 -> 203:2-40", + "204:2-31 -> 204:2-31", + "205:2-30 -> 205:2-30", + "206:2-29 -> 206:2-29", + "207:2-16 -> 207:2-16", + "208:2-21 -> 208:2-21", + "209:2-23 -> 209:2-23", + "210:2-24 -> 210:2-24", + "211:2-25 -> 211:2-25", + "212:2-19 -> 212:2-19", + "213:2-29 -> 213:2-29", + "214:2-30 -> 214:2-30", + "215:2-28 -> 215:2-28", + "216:2-36 -> 216:2-36", + "217:2-29 -> 217:2-29", + "218:2-24 -> 218:2-24", + "219:2-32 -> 219:2-32", + "220:2-13 -> 220:2-13", + "221:2-19 -> 221:2-19", + "222:2-17 -> 222:2-17", + "223:2-18 -> 223:2-18", + "224:2-19 -> 224:2-19", + "225:2-15 -> 225:2-15", + "226:2-17 -> 226:2-17", + "227:2-14 -> 227:2-14", + "228:2-20 -> 228:2-20", + "229:2-22 -> 229:2-22", + "230:2-28 -> 230:2-28", + "231:2-26 -> 231:2-26", + "232:2-27 -> 232:2-27", + "233:2-28 -> 233:2-28", + "234:2-24 -> 234:2-24", + "235:2-25 -> 235:2-25", + "236:2-26 -> 236:2-26", + "237:2-23 -> 237:2-23", + "238:0 -> 238:0", + "2:4 -> 240:0", + "241:2-26 -> 241:2-26", + "242:2-26 -> 242:2-26", + "243:2-21 -> 243:2-21", + "244:2-21 -> 244:2-21", + "245:2-16 -> 245:2-16", + "246:2-16 -> 246:2-16", + "247:2-16 -> 247:2-16", + "248:2-17 -> 248:2-17", + "249:2-17 -> 249:2-17", + "250:2-14 -> 250:2-14", + "251:2-14 -> 251:2-14", + "252:2-19 -> 252:2-19", + "253:2-40 -> 253:2-40", + "254:2-31 -> 254:2-31", + "255:2-30 -> 255:2-30", + "256:2-29 -> 256:2-29", + "257:2-16 -> 257:2-16", + "258:2-21 -> 258:2-21", + "259:2-23 -> 259:2-23", + "260:2-24 -> 260:2-24", + "261:2-25 -> 261:2-25", + "262:2-19 -> 262:2-19", + "263:2-29 -> 263:2-29", + "264:2-30 -> 264:2-30", + "265:2-28 -> 265:2-28", + "266:2-36 -> 266:2-36", + "267:2-29 -> 267:2-29", + "268:2-24 -> 268:2-24", + "269:2-32 -> 269:2-32", + "270:2-13 -> 270:2-13", + "271:2-19 -> 271:2-19", + "272:2-17 -> 272:2-17", + "273:2-18 -> 273:2-18", + "274:2-19 -> 274:2-19", + "275:2-15 -> 275:2-15", + "276:2-17 -> 276:2-17", + "277:2-14 -> 277:2-14", + "278:2-20 -> 278:2-20", + "279:2-22 -> 279:2-22", + "280:2-28 -> 280:2-28", + "281:2-26 -> 281:2-26", + "282:2-27 -> 282:2-27", + "283:2-28 -> 283:2-28", + "284:2-24 -> 284:2-24", + "285:2-25 -> 285:2-25", + "286:2-26 -> 286:2-26", + "287:2-23 -> 287:2-23", + "288:0 -> 288:0", + "2:4 -> 290:0", + "291:2-26 -> 291:2-26", + "292:2-26 -> 292:2-26", + "293:2-21 -> 293:2-21", + "294:2-21 -> 294:2-21", + "295:2-16 -> 295:2-16", + "296:2-16 -> 296:2-16", + "297:2-16 -> 297:2-16", + "298:2-17 -> 298:2-17", + "299:2-17 -> 299:2-17", + "300:2-14 -> 300:2-14", + "301:2-14 -> 301:2-14", + "302:2-19 -> 302:2-19", + "303:2-40 -> 303:2-40", + "304:2-31 -> 304:2-31", + "305:2-30 -> 305:2-30", + "306:2-29 -> 306:2-29", + "307:2-16 -> 307:2-16", + "308:2-21 -> 308:2-21", + "309:2-23 -> 309:2-23", + "310:2-24 -> 310:2-24", + "311:2-25 -> 311:2-25", + "312:2-19 -> 312:2-19", + "313:2-29 -> 313:2-29", + "314:2-30 -> 314:2-30", + "315:2-28 -> 315:2-28", + "316:2-36 -> 316:2-36", + "317:2-29 -> 317:2-29", + "318:2-24 -> 318:2-24", + "319:2-32 -> 319:2-32", + "320:2-13 -> 320:2-13", + "321:2-19 -> 321:2-19", + "322:2-17 -> 322:2-17", + "323:2-18 -> 323:2-18", + "324:2-19 -> 324:2-19", + "325:2-15 -> 325:2-15", + "326:2-17 -> 326:2-17", + "327:2-14 -> 327:2-14", + "328:2-20 -> 328:2-20", + "329:2-22 -> 329:2-22", + "330:2-28 -> 330:2-28", + "331:2-26 -> 331:2-26", + "332:2-27 -> 332:2-27", + "333:2-28 -> 333:2-28", + "334:2-24 -> 334:2-24", + "335:2-25 -> 335:2-25", + "336:2-26 -> 336:2-26", + "337:2-23 -> 337:2-23", + "338:0 -> 338:0", ] `) }) diff --git a/tests/syntax-svelte.test.js b/tests/syntax-svelte.test.js index d354eee42..b6df41f13 100644 --- a/tests/syntax-svelte.test.js +++ b/tests/syntax-svelte.test.js @@ -20,7 +20,7 @@ test('it detects svelte based on the file extension', () => { --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } - @media (width >= 1024px) { + @media (min-width: 1024px) { .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); @@ -66,7 +66,7 @@ test('using raw with svelte extension', () => { --tw-bg-opacity: 1; background-color: rgb(239 68 68 / var(--tw-bg-opacity)); } - @media (width >= 1024px) { + @media (min-width: 1024px) { .lg\:hover\:bg-blue-500:hover { --tw-bg-opacity: 1; background-color: rgb(59 130 246 / var(--tw-bg-opacity)); diff --git a/tests/tailwind-screens.test.js b/tests/tailwind-screens.test.js index 91eb93c6e..009c02bc3 100644 --- a/tests/tailwind-screens.test.js +++ b/tests/tailwind-screens.test.js @@ -19,7 +19,7 @@ test('class variants are inserted at `@tailwind variants`', async () => { .hover\:font-bold:hover { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } @@ -50,7 +50,7 @@ test('`@tailwind screens` works as an alias for `@tailwind variants`', async () .hover\:font-bold:hover { font-weight: 700; } - @media (width >= 768px) { + @media (min-width: 768px) { .md\:font-bold { font-weight: 700; } diff --git a/tests/util/defaults.js b/tests/util/defaults.js index bea97d338..77749244c 100644 --- a/tests/util/defaults.js +++ b/tests/util/defaults.js @@ -9,7 +9,106 @@ export function defaults({ defaultRingColor = `#3b82f680` } = {}) { return css` *, :before, - :after, + :after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: ${defaultRingColor}; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + } + + ::-webkit-backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: ${defaultRingColor}; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; + } + ::backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; diff --git a/tests/variant-grouping.test.skip.js b/tests/variant-grouping.test.skip.js index 156d4a5cf..aba113783 100644 --- a/tests/variant-grouping.test.skip.js +++ b/tests/variant-grouping.test.skip.js @@ -38,7 +38,7 @@ it('should be possible to group variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 768px) { + @media (min-width: 768px) { .md\:\(underline\2c italic\) { font-style: italic; text-decoration-line: underline; @@ -97,7 +97,7 @@ it('should be possible to group multiple variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 768px) { + @media (min-width: 768px) { @media (prefers-color-scheme: dark) { .md\:dark\:\(underline\2c italic\) { font-style: italic; @@ -123,7 +123,7 @@ it('should be possible to group nested grouped variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 768px) { + @media (min-width: 768px) { .md\:\(underline\2c italic\2c hover\:\(uppercase\2c font-bold\)\) { font-style: italic; text-decoration-line: underline; @@ -155,7 +155,7 @@ it('should be possible to use nested multiple grouped variants', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 768px) { + @media (min-width: 768px) { .md\:\(text-black\2c dark\:\(text-white\2c hover\:focus\:text-gray-100\)\) { --tw-text-opacity: 1; color: rgb(0 0 0 / var(--tw-text-opacity)); @@ -195,7 +195,7 @@ it('should be possible to mix and match nesting and different variant combinatio return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (width >= 768px) { + @media (min-width: 768px) { .md\:\[\&\>\*\]\:\(text-black\2c dark\:\(text-white\2c hover\:\[\@supports\(color\:green\)\]\:\[\&\:nth-child\(2n\=1\)\]\:text-gray-100\)\) diff --git a/tests/variants.test.css b/tests/variants.test.css index 57291001a..3832e0ddb 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -1,6 +1,103 @@ *, :before, -:after, +:after { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} +::-webkit-backdrop { + --tw-border-spacing-x: 0; + --tw-border-spacing-y: 0; + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-gradient-from-position: ; + --tw-gradient-via-position: ; + --tw-gradient-to-position: ; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #3b82f680; + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} ::backdrop { --tw-border-spacing-x: 0; --tw-border-spacing-y: 0; @@ -51,17 +148,31 @@ --tw-backdrop-sepia: ; } .first-letter\:flex:first-letter, -.first-line\:flex:first-line, -.marker\:flex ::marker, -.marker\:flex::marker, +.first-line\:flex:first-line { + display: flex; +} +.marker\:flex ::marker { + display: flex; +} +.marker\:flex::marker { + display: flex; +} .selection\:flex ::selection, .selection\:flex::selection { display: flex; } +.file\:flex::-webkit-file-upload-button { + display: flex; +} .file\:flex::file-selector-button { display: flex; } -.placeholder\:flex::placeholder, +.placeholder\:flex::placeholder { + display: flex; +} +.backdrop\:flex::-webkit-backdrop { + display: flex; +} .backdrop\:flex::backdrop { display: flex; } @@ -105,13 +216,20 @@ .hover\:flex:hover { display: flex; } +.file\:hover\:flex:hover::-webkit-file-upload-button { + display: flex; +} .file\:hover\:flex:hover::file-selector-button { display: flex; } .open\:hover\:flex:hover[open], .focus\:flex:focus, -.focus\:hover\:flex:hover:focus, -.focus-visible\:flex:focus-visible, +.focus\:hover\:flex:hover:focus { + display: flex; +} +.focus-visible\:flex:focus-visible { + display: flex; +} .active\:flex:active, .enabled\:flex:enabled, .disabled\:flex:disabled, @@ -189,10 +307,6 @@ :-webkit-any([dir='rtl'] .rtl\:flex) { display: flex; } -.open\:hover\:flex:hover[open], -.focus\:flex:focus, -.focus\:hover\:flex:hover:focus, -.focus-visible\:flex:focus-visible, .active\:flex:active, .enabled\:flex:enabled, .disabled\:flex:disabled, @@ -300,31 +414,31 @@ display: flex; } } -@media (width >= 640px) { +@media (min-width: 640px) { .sm\:flex, .sm\:active\:flex:active { display: flex; } } -@media (width >= 768px) { +@media (min-width: 768px) { .md\:flex, .group:focus .md\:group-focus\:flex { display: flex; } } -@media (width >= 1024px) { +@media (min-width: 1024px) { .lg\:flex, :is(.dark .lg\:dark\:flex) { display: flex; } } -@media (width >= 1280px) { +@media (min-width: 1280px) { .xl\:flex, :is(.dark .xl\:dark\:disabled\:flex:disabled) { display: flex; } } -@media (width >= 1536px) { +@media (min-width: 1536px) { .\32 xl\:flex { display: flex; } diff --git a/tests/variants.test.js b/tests/variants.test.js index 1e88aa4e1..f2a2de075 100644 --- a/tests/variants.test.js +++ b/tests/variants.test.js @@ -37,9 +37,15 @@ test('order matters and produces different behaviour', () => { return run('@tailwind utilities', config).then((result) => { expect(result.css).toMatchFormattedCss(css` + .file\:hover\:\[--value\:2\]:hover::-webkit-file-upload-button { + --value: 2; + } .file\:hover\:\[--value\:2\]:hover::file-selector-button { --value: 2; } + .hover\:file\:\[--value\:1\]::-webkit-file-upload-button:hover { + --value: 1; + } .hover\:file\:\[--value\:1\]::file-selector-button:hover { --value: 1; } @@ -318,7 +324,7 @@ test('custom addVariant with more complex media query params', () => { return run('@tailwind components;@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media screen and (width <= 600px) { + @media screen and (max-width: 600px) { .magic\:text-center { text-align: center; } @@ -491,7 +497,7 @@ it('should be possible to use responsive modifiers that are defined with special return run('@tailwind utilities', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (width <= 399px) { + @media (max-width: 399px) { .\ { return expect(result.css).toMatchFormattedCss(css` - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:underline { text-decoration-line: underline; } @@ -538,31 +544,31 @@ it('variants for utilities should not be produced in a file without a utilities return run('@tailwind components', config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:container { width: 100%; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:container { max-width: 640px; } } - @media (width >= 768px) { + @media (min-width: 768px) { .sm\:container { max-width: 768px; } } - @media (width >= 1024px) { + @media (min-width: 1024px) { .sm\:container { max-width: 1024px; } } - @media (width >= 1280px) { + @media (min-width: 1280px) { .sm\:container { max-width: 1280px; } } - @media (width >= 1536px) { + @media (min-width: 1536px) { .sm\:container { max-width: 1536px; } @@ -622,7 +628,7 @@ it('appends variants to the correct place when using postcss documents', () => { .underline { text-decoration-line: underline; } - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:underline { text-decoration-line: underline; } @@ -654,7 +660,7 @@ it('variants support multiple, grouped selectors (html)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:base1 .foo, .sm\:base1 .bar, .sm\:base2 .bar .base2-foo { @@ -687,7 +693,7 @@ it('variants support multiple, grouped selectors (apply)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (width >= 640px) { + @media (min-width: 640px) { .baz .foo, .baz .bar { color: red; @@ -716,7 +722,7 @@ it('variants only picks the used selectors in a group (html)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (width >= 640px) { + @media (min-width: 640px) { .sm\:b { color: red; } @@ -747,7 +753,7 @@ it('variants only picks the used selectors in a group (apply)', () => { return run(input, config).then((result) => { return expect(result.css).toMatchFormattedCss(css` - @media (width >= 640px) { + @media (min-width: 640px) { .baz { color: red; } @@ -915,7 +921,7 @@ test('class inside pseudo-class function :has', () => { html:has(.hover\:foo:hover) { color: green; } - @media (width >= 640px) { + @media (min-width: 640px) { :where(.sm\:foo) { color: red; } @@ -995,7 +1001,7 @@ test('variants with slashes in them work', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (aspect-ratio >= 1 / 10) { + @media (min-aspect-ratio: 1 / 10) { .ar-1\/10\:flex { display: flex; } @@ -1031,7 +1037,7 @@ test('variants with slashes support modifiers', () => { return run(input, config).then((result) => { expect(result.css).toMatchFormattedCss(css` - @media (aspect-ratio >= 1 / 10) and (foo: 20) { + @media (min-aspect-ratio: 1 / 10) and (foo: 20) { .ar-1\/10\/20\:flex { display: flex; } From 3be258c218091414a018e6c65286b636763747a2 Mon Sep 17 00:00:00 2001 From: cunzaizhuyi <877824709@qq.com> Date: Sun, 11 Jun 2023 23:06:03 +0800 Subject: [PATCH 57/85] chore: make sentence smooth (#11407) * chore: make sentence smooth * chore: everything typo * chore: its * feat: e.g. * chore: a => an; remove repeated `to` * Update offsets.js * Update generateRules.js --------- Co-authored-by: Adam Wathan --- src/lib/generateRules.js | 6 +++--- src/lib/offsets.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib/generateRules.js b/src/lib/generateRules.js index 3aec15951..67344d370 100644 --- a/src/lib/generateRules.js +++ b/src/lib/generateRules.js @@ -45,7 +45,7 @@ function* candidatePermutations(candidate) { let bracketIdx = candidate.indexOf('[') // If character before `[` isn't a dash or a slash, this isn't a dynamic class - // eg. string[] + // e.g. string[] if (candidate[bracketIdx - 1] === '-') { dashIdx = bracketIdx - 1 } else if (candidate[bracketIdx - 1] === '/') { @@ -455,9 +455,9 @@ function isParsableNode(node) { } function isParsableCssValue(property, value) { - // We don't want to to treat [https://example.com] as a custom property + // We don't want to treat [https://example.com] as a custom property // Even though, according to the CSS grammar, it's a totally valid CSS declaration - // So we short-circuit here by checking if the custom property looks like a url + // So we short-circuit here by checking if the custom property looks like a URL if (looksLikeUri(`${property}:${value}`)) { return false } diff --git a/src/lib/offsets.js b/src/lib/offsets.js index a43ebe4f3..0ecc04b77 100644 --- a/src/lib/offsets.js +++ b/src/lib/offsets.js @@ -23,7 +23,7 @@ import { remapBitfield } from './remap-bitfield.js' * @property {bigint} arbitrary 0n if false, 1n if true * @property {bigint} variants Dynamic size. 1 bit per registered variant. 0n means no variants * @property {bigint} parallelIndex Rule index for the parallel variant. 0 if not applicable. - * @property {bigint} index Index of the rule / utility in it's given *parent* layer. Monotonically increasing. + * @property {bigint} index Index of the rule / utility in its given *parent* layer. Monotonically increasing. * @property {VariantOption[]} options Some information on how we can sort arbitrary variants */ @@ -302,7 +302,7 @@ export class Offsets { let mapping = this.recalculateVariantOffsets() // No arbitrary variants? Nothing to do. - // Everyhing already in order? Nothing to do. + // Everything already in order? Nothing to do. if (mapping.length === 0) { return list } @@ -354,7 +354,7 @@ function max(nums) { * Using `.sort()` without a custom compare function is faster * But you can only use that if you're sorting an array of * only strings. If you're sorting strings inside objects - * or arrays, you need must use a custom compare function. + * or arrays, you need to use a custom compare function. * * @param {string} a * @param {string} b From 86f9c6f09270a9da6fee77909863444b52e2f9b6 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 12 Jun 2023 22:07:06 +0200 Subject: [PATCH 58/85] Simplify browserslist setup by relying on `defaults` (#11412) * use `defaults` for `browserslist` + some features that we require for Tailwind to work. * simplify Lightning CSS features Always transpile `Nesting`, never transpile `LogicalProperties`. * bump caniuse-lite (`npx browserslist@latest --update-db`) * reflect changes in the tests * update changelog --- CHANGELOG.md | 2 +- package-lock.json | 18 +++++++++--------- package.json | 3 +-- src/cli/build/plugin.js | 15 ++------------- src/plugin.js | 17 ++--------------- tests/variants.test.css | 4 +++- 6 files changed, 18 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 785ab7d9f..324c161c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,7 +28,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add `svh`, `lvh`, and `dvh` values to default `height`/`min-height`/`max-height` theme ([#11317](https://github.com/tailwindlabs/tailwindcss/pull/11317)) - Add `has-*` variants for `:has(...)` pseudo-class ([#11318](https://github.com/tailwindlabs/tailwindcss/pull/11318)) - Add `text-wrap` utilities including `text-balance` ([#11320](https://github.com/tailwindlabs/tailwindcss/pull/11320)) -- Explicitly configure Lightning CSS features, and prefer user browserslist over default browserslist ([#11402](https://github.com/tailwindlabs/tailwindcss/pull/11402)) +- Explicitly configure Lightning CSS features, and prefer user browserslist over default browserslist ([#11402](https://github.com/tailwindlabs/tailwindcss/pull/11402), [#11412](https://github.com/tailwindlabs/tailwindcss/pull/11412)) ### Changed diff --git a/package-lock.json b/package-lock.json index 057500410..18e54089b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5847,9 +5847,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001495", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", - "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", + "version": "1.0.30001502", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", + "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==", "funding": [ { "type": "opencollective", @@ -20141,9 +20141,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001495", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", - "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==" + "version": "1.0.30001502", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", + "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==" }, "chalk": { "version": "4.1.2", @@ -30527,9 +30527,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001495", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", - "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==" + "version": "1.0.30001502", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001502.tgz", + "integrity": "sha512-AZ+9tFXw1sS0o0jcpJQIXvFTOB/xGiQ4OQ2t98QX3NDn2EZTSRBC801gxrsGgViuq2ak/NLkNgSNEPtCr5lfKg==" }, "chalk": { "version": "4.1.2", diff --git a/package.json b/package.json index ea3443937..d3b1752b3 100644 --- a/package.json +++ b/package.json @@ -87,8 +87,7 @@ "sucrase": "^3.32.0" }, "browserslist": [ - "chrome >= 103", - "firefox >= 102", + "defaults and supports css-variables and supports css-matches-pseudo", "safari >= 14" ], "jest": { diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index 968bd3c88..89bcbe95f 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -28,23 +28,12 @@ import { flagEnabled } from '../../featureFlags' async function lightningcss(result, { map = true, minify = true } = {}) { try { - let includeFeatures = Features.Nesting - let excludeFeatures = 0 - let resolvedBrowsersListConfig = browserslist.findConfig( result.opts.from ?? process.cwd() )?.defaults let defaultBrowsersListConfig = pkg.browserslist let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig - if (browsersListConfig.join(',') === defaultBrowsersListConfig.join(',')) { - includeFeatures |= - Features.ColorFunction | Features.OklabColors | Features.LabColors | Features.P3Colors - - excludeFeatures |= - Features.HexAlphaColors | Features.LogicalProperties | Features.SpaceSeparatedColorNotation - } - let transformed = lightning.transform({ filename: result.opts.from || 'input.css', code: Buffer.from(result.css, 'utf-8'), @@ -55,8 +44,8 @@ async function lightningcss(result, { map = true, minify = true } = {}) { drafts: { nesting: true, }, - include: includeFeatures, - exclude: excludeFeatures, + include: Features.Nesting, + exclude: Features.LogicalProperties, }) return Object.assign(result, { diff --git a/src/plugin.js b/src/plugin.js index 70222f319..9efabde34 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -49,25 +49,12 @@ module.exports = function tailwindcss(configOrPath) { let intermediateMap = intermediateResult.map?.toJSON?.() ?? map try { - let includeFeatures = Features.Nesting - let excludeFeatures = 0 - let resolvedBrowsersListConfig = browserslist.findConfig( result.opts.from ?? process.cwd() )?.defaults let defaultBrowsersListConfig = require('../package.json').browserslist let browsersListConfig = resolvedBrowsersListConfig ?? defaultBrowsersListConfig - if (browsersListConfig.join(',') === defaultBrowsersListConfig.join(',')) { - includeFeatures |= - Features.ColorFunction | Features.OklabColors | Features.LabColors | Features.P3Colors - - excludeFeatures |= - Features.HexAlphaColors | - Features.LogicalProperties | - Features.SpaceSeparatedColorNotation - } - let transformed = lightningcss.transform({ filename: result.opts.from, code: Buffer.from(intermediateResult.css), @@ -81,8 +68,8 @@ module.exports = function tailwindcss(configOrPath) { nonStandard: { deepSelectorCombinator: true, }, - include: includeFeatures, - exclude: excludeFeatures, + include: Features.Nesting, + exclude: Features.LogicalProperties, }) let code = transformed.code.toString() diff --git a/tests/variants.test.css b/tests/variants.test.css index 3832e0ddb..22fc0691d 100644 --- a/tests/variants.test.css +++ b/tests/variants.test.css @@ -157,7 +157,9 @@ .marker\:flex::marker { display: flex; } -.selection\:flex ::selection, +.selection\:flex ::selection { + display: flex; +} .selection\:flex::selection { display: flex; } From a7a1f9347c69d7d911c89846e7bceb6ba56d6398 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Fri, 16 Jun 2023 17:56:11 +0000 Subject: [PATCH 59/85] Update sass to version 1.63.4 --- integrations/rollup-sass/package.json | 2 +- package-lock.json | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/integrations/rollup-sass/package.json b/integrations/rollup-sass/package.json index 13b8e2494..39b62d90e 100644 --- a/integrations/rollup-sass/package.json +++ b/integrations/rollup-sass/package.json @@ -20,6 +20,6 @@ "devDependencies": { "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.1" + "sass": "^1.63.4" } } diff --git a/package-lock.json b/package-lock.json index 18e54089b..e7d49446c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,7 +101,7 @@ "devDependencies": { "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.1" + "sass": "1.63.4" } }, "integrations/tailwindcss-cli": { @@ -13536,9 +13536,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.62.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz", - "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==", + "version": "1.63.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.4.tgz", + "integrity": "sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -18481,7 +18481,7 @@ "requires": { "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.1" + "sass": "1.63.4" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -25681,9 +25681,9 @@ "dev": true }, "sass": { - "version": "1.62.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz", - "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==", + "version": "1.63.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.4.tgz", + "integrity": "sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -28867,7 +28867,7 @@ "requires": { "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "^1.62.1" + "sass": "1.63.4" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -36067,9 +36067,9 @@ "dev": true }, "sass": { - "version": "1.62.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.62.1.tgz", - "integrity": "sha512-NHpxIzN29MXvWiuswfc1W3I0N8SXBd8UR26WntmDlRYf0bSADnwnOjsyMZ3lMezSlArD33Vs3YFhp7dWvL770A==", + "version": "1.63.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.63.4.tgz", + "integrity": "sha512-Sx/+weUmK+oiIlI+9sdD0wZHsqpbgQg8wSwSnGBjwb5GwqFhYNwwnI+UWZtLjKvKyFlKkatRK235qQ3mokyPoQ==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", From ac6e8733e92593b7dcb56c79872cdb2d18dba84a Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Fri, 16 Jun 2023 21:12:09 +0000 Subject: [PATCH 60/85] Update eslint to version 8.42.0 --- package-lock.json | 6 +++--- package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index e7d49446c..cf5fb092c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -101,7 +101,7 @@ "devDependencies": { "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "1.63.4" + "sass": "^1.63.4" } }, "integrations/tailwindcss-cli": { @@ -18481,7 +18481,7 @@ "requires": { "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "1.63.4" + "sass": "^1.63.4" } }, "@tailwindcss/integrations-tailwindcss-cli": { @@ -28867,7 +28867,7 @@ "requires": { "rollup": "^3.23.0", "rollup-plugin-postcss": "^4.0.2", - "sass": "1.63.4" + "sass": "^1.63.4" } }, "@tailwindcss/integrations-tailwindcss-cli": { diff --git a/package.json b/package.json index d3b1752b3..7fb3d7c30 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "concurrently": "^8.0.1", - "eslint": "^8.39.0", + "eslint": "^8.42.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "jest": "^29.5.0", From 776d5bf614cbc5ee5c3979cac8b2fcc65a2b7b17 Mon Sep 17 00:00:00 2001 From: "depfu[bot]" <23717796+depfu[bot]@users.noreply.github.com> Date: Mon, 19 Jun 2023 06:25:46 +0000 Subject: [PATCH 61/85] Update rollup to version 3.25.1 --- integrations/rollup-sass/package.json | 2 +- integrations/rollup/package.json | 2 +- package-lock.json | 231 +++++++++++++------------- 3 files changed, 117 insertions(+), 118 deletions(-) diff --git a/integrations/rollup-sass/package.json b/integrations/rollup-sass/package.json index 39b62d90e..d61037181 100644 --- a/integrations/rollup-sass/package.json +++ b/integrations/rollup-sass/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "rollup": "^3.23.0", + "rollup": "^3.25.1", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.63.4" } diff --git a/integrations/rollup/package.json b/integrations/rollup/package.json index c927b752a..4fb815e97 100644 --- a/integrations/rollup/package.json +++ b/integrations/rollup/package.json @@ -18,7 +18,7 @@ } }, "devDependencies": { - "rollup": "^3.23.0", + "rollup": "^3.25.1", "rollup-plugin-postcss": "^4.0.2" } } diff --git a/package-lock.json b/package-lock.json index cf5fb092c..8d0a4f06c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,7 @@ "@swc/jest": "^0.2.26", "@swc/register": "^0.1.10", "concurrently": "^8.0.1", - "eslint": "^8.39.0", + "eslint": "^8.42.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "jest": "^29.5.0", @@ -91,7 +91,7 @@ "name": "@tailwindcss/integrations-rollup", "version": "0.0.0", "devDependencies": { - "rollup": "^3.23.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2" } }, @@ -99,7 +99,7 @@ "name": "@tailwindcss/integrations-rollup-sass", "version": "0.0.0", "devDependencies": { - "rollup": "^3.23.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.63.4" } @@ -1614,14 +1614,14 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -1670,18 +1670,19 @@ } }, "node_modules/@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -1705,8 +1706,9 @@ }, "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", - "dev": true, - "license": "BSD-3-Clause" + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -7236,16 +7238,16 @@ } }, "node_modules/eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.43.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -7255,8 +7257,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -7264,13 +7266,12 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -7341,9 +7342,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -7426,14 +7427,14 @@ } }, "node_modules/espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "dependencies": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -8468,10 +8469,11 @@ "dev": true, "license": "ISC" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "dev": true, - "license": "MIT" + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true }, "node_modules/has": { "version": "1.0.3", @@ -10210,11 +10212,6 @@ "jiti": "bin/jiti.js" } }, - "node_modules/js-sdsl": { - "version": "4.1.4", - "dev": true, - "license": "MIT" - }, "node_modules/js-tokens": { "version": "4.0.0", "dev": true, @@ -12826,9 +12823,9 @@ } }, "node_modules/rollup": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", - "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -16670,14 +16667,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -16713,13 +16710,15 @@ } }, "@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.8", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -16733,6 +16732,8 @@ }, "@humanwhocodes/object-schema": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@istanbuljs/load-nyc-config": { @@ -18472,14 +18473,14 @@ "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "^3.23.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "^3.23.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.63.4" } @@ -21159,16 +21160,16 @@ "dev": true }, "eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.43.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -21178,8 +21179,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -21187,13 +21188,12 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -21273,20 +21273,20 @@ } }, "eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true }, "espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -22051,8 +22051,10 @@ "version": "4.2.10", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "has": { @@ -23405,10 +23407,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" }, - "js-sdsl": { - "version": "4.1.4", - "dev": true - }, "js-tokens": { "version": "4.0.0", "dev": true @@ -25216,9 +25214,9 @@ } }, "rollup": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", - "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", "dev": true, "requires": { "fsevents": "~2.3.2" @@ -26379,7 +26377,7 @@ "concurrently": "^8.0.1", "didyoumean": "^1.2.2", "dlv": "^1.1.3", - "eslint": "^8.39.0", + "eslint": "^8.42.0", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^4.2.1", "fast-glob": "^3.2.12", @@ -27056,14 +27054,14 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", - "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", + "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.1", + "espree": "^9.5.2", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -27099,13 +27097,15 @@ } }, "@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz", + "integrity": "sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg==", "dev": true }, "@humanwhocodes/config-array": { - "version": "0.11.8", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", @@ -27119,6 +27119,8 @@ }, "@humanwhocodes/object-schema": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", "dev": true }, "@istanbuljs/load-nyc-config": { @@ -28858,14 +28860,14 @@ "@tailwindcss/integrations-rollup": { "version": "file:integrations/rollup", "requires": { - "rollup": "^3.23.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2" } }, "@tailwindcss/integrations-rollup-sass": { "version": "file:integrations/rollup-sass", "requires": { - "rollup": "^3.23.0", + "rollup": "3.25.1", "rollup-plugin-postcss": "^4.0.2", "sass": "^1.63.4" } @@ -31545,16 +31547,16 @@ "dev": true }, "eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.43.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.43.0.tgz", + "integrity": "sha512-aaCpf2JqqKesMFGgmRPessmVKjcGXqdlAYLLC3THM8t5nBRZRQ+st5WM/hoJXkdioEXLLbXgclUpM0TXo5HX5Q==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint/eslintrc": "^2.0.3", + "@eslint/js": "8.43.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", @@ -31564,8 +31566,8 @@ "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-visitor-keys": "^3.4.1", + "espree": "^9.5.2", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -31573,13 +31575,12 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -31659,20 +31660,20 @@ } }, "eslint-visitor-keys": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", - "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", + "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", "dev": true }, "espree": { - "version": "9.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", - "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "version": "9.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", + "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", "dev": true, "requires": { "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.0" + "eslint-visitor-keys": "^3.4.1" } }, "esprima": { @@ -32437,8 +32438,10 @@ "version": "4.2.10", "dev": true }, - "grapheme-splitter": { - "version": "1.0.4", + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, "has": { @@ -33791,10 +33794,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.18.2.tgz", "integrity": "sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==" }, - "js-sdsl": { - "version": "4.1.4", - "dev": true - }, "js-tokens": { "version": "4.0.0", "dev": true @@ -35602,9 +35601,9 @@ } }, "rollup": { - "version": "3.23.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.0.tgz", - "integrity": "sha512-h31UlwEi7FHihLe1zbk+3Q7z1k/84rb9BSwmBSr/XjOCEaBJ2YyedQDuM0t/kfOS0IxM+vk1/zI9XxYj9V+NJQ==", + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.25.1.tgz", + "integrity": "sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==", "dev": true, "requires": { "fsevents": "~2.3.2" From a5305aa84ee82f5f0ed78ab6c36cd211d791c0b3 Mon Sep 17 00:00:00 2001 From: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Date: Wed, 14 Jun 2023 09:40:04 -0400 Subject: [PATCH 62/85] Super hacky POC --- src/lib/setupTrackingContext.js | 15 ++++++++----- src/plugin.js | 21 ++++++++++++++++++- tests/css-configuration.test.js | 37 +++++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+), 6 deletions(-) create mode 100644 tests/css-configuration.test.js diff --git a/src/lib/setupTrackingContext.js b/src/lib/setupTrackingContext.js index 70e7cb684..419dd8594 100644 --- a/src/lib/setupTrackingContext.js +++ b/src/lib/setupTrackingContext.js @@ -28,7 +28,7 @@ function getCandidateFiles(context, tailwindConfig) { } // Get the config object based on a path -function getTailwindConfig(configOrPath) { +function getTailwindConfig(configOrPath, cssThemeValues) { let userConfigPath = resolveConfigPath(configOrPath) if (userConfigPath !== null) { @@ -56,14 +56,19 @@ function getTailwindConfig(configOrPath) { for (let file of newDeps) { delete require.cache[file] } - let newConfig = validateConfig(resolveConfig(loadConfig(userConfigPath))) + let newConfig = validateConfig( + resolveConfig({ theme: cssThemeValues }, loadConfig(userConfigPath)) + ) let newHash = hash(newConfig) configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified]) return [newConfig, userConfigPath, newHash, newDeps] } // It's a plain object, not a path - let newConfig = resolveConfig(configOrPath?.config ?? configOrPath ?? {}) + let newConfig = resolveConfig( + { theme: cssThemeValues }, + configOrPath?.config ?? configOrPath ?? {} + ) newConfig = validateConfig(newConfig) @@ -75,11 +80,11 @@ function getTailwindConfig(configOrPath) { // Retrieve an existing context from cache if possible (since contexts are unique per // source path), or set up a new one (including setting up watchers and registering // plugins) then return it -export default function setupTrackingContext(configOrPath) { +export default function setupTrackingContext(configOrPath, cssThemeValues) { return ({ tailwindDirectives, registerDependency }) => { return (root, result) => { let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = - getTailwindConfig(configOrPath) + getTailwindConfig(configOrPath, cssThemeValues) let contextDependencies = new Set(configDependencies) diff --git a/src/plugin.js b/src/plugin.js index 9efabde34..d617b55cf 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -23,7 +23,26 @@ module.exports = function tailwindcss(configOrPath) { // path for the file being processed configOrPath = findAtConfigPath(root, result) ?? configOrPath - let context = setupTrackingContext(configOrPath) + // Begin CSS-first theme configuration proof-of-concept + let themeValues = { extend: { colors: {} } } + + root.each((node) => { + if (node.type === 'rule' && node.selector === ':theme') { + // Walk :theme pseudo and extract values + node.walkDecls((decl) => { + if (decl.prop.startsWith('--colors-')) { + themeValues.extend.colors[decl.prop.slice(9)] = decl.value + } + }) + + node.remove() + } + }) + + // context.tailwindConfig.theme + // End CSS-first theme configuration proof-of-concept + + let context = setupTrackingContext(configOrPath, themeValues) if (root.type === 'document') { let roots = root.nodes.filter((node) => node.type === 'root') diff --git a/tests/css-configuration.test.js b/tests/css-configuration.test.js new file mode 100644 index 000000000..470801809 --- /dev/null +++ b/tests/css-configuration.test.js @@ -0,0 +1,37 @@ +import { run, html, css } from './util/run' + +test('it does something', () => { + let config = { + darkMode: 'class', + content: [ + { + raw: html` +
+
+ `, + }, + ], + } + + return run( + css` + @tailwind utilities; + + :theme { + --colors-potato: #facade; + } + `, + config + ).then((result) => { + expect(result.css).toMatchFormattedCss(css` + .text-black { + --tw-text-opacity: 1; + color: rgb(0 0 0 / var(--tw-text-opacity)); + } + .text-potato { + --tw-text-opacity: 1; + color: rgb(250 202 222 / var(--tw-text-opacity)); + } + `) + }) +}) From ba7d3be00eed43fadcfff938dcad825123ca6f7b Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 12:11:19 -0400 Subject: [PATCH 63/85] Refactor --- src/lib/parseCssConfig.js | 102 ++++++++++++++++++++++++++++++++++++++ src/plugin.js | 21 ++------ 2 files changed, 105 insertions(+), 18 deletions(-) create mode 100644 src/lib/parseCssConfig.js diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js new file mode 100644 index 000000000..99a9acfd8 --- /dev/null +++ b/src/lib/parseCssConfig.js @@ -0,0 +1,102 @@ +// @ts-check + +/** + * Find and convert the `:theme` rule to a configuration object + * This is merged with the user's JS config + * It should take precedence over the JS config + * + * @param {import('postcss').Root} root + */ +export function parseCssConfig(root) { + let config = { extend: { colors: {} } } + + let theme = root.nodes.find(node => node.type === 'rule' && node.selector === ':theme') + if (!theme) return config + + theme.walkDecls((decl) => { + if (decl.prop.startsWith('--')) { + parseVariable(config, decl.prop.slice(2), decl.value) + } else { + // Only CSS variables are allowed in the theme rule + // TODO: Maybe turn this into an error? + decl.remove() + } + }) + + theme.remove() + + return config +} + +let prefixPluginMap = { + 'colors': 'colors', + 'spacing': 'spacing', + 'font-family': 'fontFamily', + 'font-size': 'fontSize', + 'shadow': 'boxShadow', +} + +/** + * Parse a key into one or more actions that modify the config and/or CSS + * + * @param {*} config + * @param {string} name + * @param {string} value + */ +function parseVariable(config, name, value) { + // Parse the variable name into a config plugin and keypath + let [plugin, keypath] = parseVariableName(name, value) + + console.log({ name, plugin, keypath, value }) + + // We couldn't find a plugin for this variable, so we can't do anything with it + if (plugin === null) return + + if (keypath === null && value === 'unset') { + // when using `--some-plugin: unset` we want to reset whatever the default value is + config[plugin] = {} + + // This also means there is no reason to keep the variable in the CSS + decl.remove() + + return + } + + // When using `--some-plugin: initial` it should reset to the default value for that key + // This effectively means removing it + if (keypath === null && value === 'initial') { + delete config[plugin] + delete config.extend[plugin] + + // This also means there is no reason to keep the variable in the CSS + decl.remove() + + return + } + + // All other cases are config keys in a plugin + config.extend[plugin] ??= {} + config.extend[plugin][keypath] = value +} + +/** + * Parse a key into one or more actions that modify the config and/or CSS + * + * @param {string} name + * @param {string} value + * @returns {[plugin: string|null, keypath: string|null]} + */ +function parseVariableName(name, value) { + for (const [prefix, plugin] of Object.entries(prefixPluginMap)) { + if (!name.startsWith(prefix)) continue + + // The keypath is the part of the variable name after the prefix + let keypath = name.slice(prefix.length) + if (keypath.startsWith('-')) keypath = keypath.slice(1) + if (keypath === '') keypath = null + + return [plugin, keypath] + } + + return [null, null] +} diff --git a/src/plugin.js b/src/plugin.js index d617b55cf..396f9b54c 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -6,6 +6,7 @@ import processTailwindFeatures from './processTailwindFeatures' import { env } from './lib/sharedState' import { findAtConfigPath } from './lib/findAtConfigPath' import { handleImportAtRules } from './lib/handleImportAtRules' +import { parseCssConfig } from './lib/parseCssConfig' module.exports = function tailwindcss(configOrPath) { return { @@ -23,24 +24,8 @@ module.exports = function tailwindcss(configOrPath) { // path for the file being processed configOrPath = findAtConfigPath(root, result) ?? configOrPath - // Begin CSS-first theme configuration proof-of-concept - let themeValues = { extend: { colors: {} } } - - root.each((node) => { - if (node.type === 'rule' && node.selector === ':theme') { - // Walk :theme pseudo and extract values - node.walkDecls((decl) => { - if (decl.prop.startsWith('--colors-')) { - themeValues.extend.colors[decl.prop.slice(9)] = decl.value - } - }) - - node.remove() - } - }) - - // context.tailwindConfig.theme - // End CSS-first theme configuration proof-of-concept + // Parse any CSS-based config values from `:theme` rules + let themeValues = parseCssConfig(root) let context = setupTrackingContext(configOrPath, themeValues) From 3c38f0a39144754f833eccef09e467e16e589988 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 12:11:39 -0400 Subject: [PATCH 64/85] Expose theme variables to CSS --- src/lib/parseCssConfig.js | 3 ++- tests/css-configuration.test.js | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 99a9acfd8..b218304f7 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -23,7 +23,8 @@ export function parseCssConfig(root) { } }) - theme.remove() + // Allow the variables to be used with var() anywhere in CSS + theme.selector = ':root' return config } diff --git a/tests/css-configuration.test.js b/tests/css-configuration.test.js index 470801809..9b25c2bbc 100644 --- a/tests/css-configuration.test.js +++ b/tests/css-configuration.test.js @@ -32,6 +32,9 @@ test('it does something', () => { --tw-text-opacity: 1; color: rgb(250 202 222 / var(--tw-text-opacity)); } + :root { + --colors-potato: #facade; + } `) }) }) From 8809c6a7fb0ceaa62dab2563fb93859f45ec24bf Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 12:48:02 -0400 Subject: [PATCH 65/85] Work on implementation --- src/lib/parseCssConfig.js | 77 +++++++++++++++++++----- tests/css-configuration.test.js | 103 +++++++++++++++++++++++++++++--- 2 files changed, 157 insertions(+), 23 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index b218304f7..5020cd623 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -15,7 +15,7 @@ export function parseCssConfig(root) { theme.walkDecls((decl) => { if (decl.prop.startsWith('--')) { - parseVariable(config, decl.prop.slice(2), decl.value) + parseVariable(config, decl) } else { // Only CSS variables are allowed in the theme rule // TODO: Maybe turn this into an error? @@ -41,14 +41,12 @@ let prefixPluginMap = { * Parse a key into one or more actions that modify the config and/or CSS * * @param {*} config - * @param {string} name - * @param {string} value + * @param {import('postcss').Declaration} decl */ -function parseVariable(config, name, value) { +function parseVariable(config, decl) { // Parse the variable name into a config plugin and keypath - let [plugin, keypath] = parseVariableName(name, value) - - console.log({ name, plugin, keypath, value }) + let [name, value] = [decl.prop.slice(2), decl.value] + let [plugin, keypath, option] = parseVariableName(name) // We couldn't find a plugin for this variable, so we can't do anything with it if (plugin === null) return @@ -75,29 +73,78 @@ function parseVariable(config, name, value) { return } + // TODO: Can this happen + if (keypath === null) { + return + } + // All other cases are config keys in a plugin config.extend[plugin] ??= {} - config.extend[plugin][keypath] = value + + if (!option) { + config.extend[plugin][keypath] = value + return + } + + if (!Array.isArray(config.extend[plugin][keypath])) { + config.extend[plugin][keypath] = [ + config.extend[plugin][keypath], + {} + ] + } + + config.extend[plugin][keypath][1][option] = value } /** * Parse a key into one or more actions that modify the config and/or CSS * * @param {string} name - * @param {string} value - * @returns {[plugin: string|null, keypath: string|null]} + * @returns {[plugin: string|null, keypath: string|null, option: string|null]} */ -function parseVariableName(name, value) { +function parseVariableName(name) { + // Unescape the name if needed + // This is needed for CSS variables that contain special characters + name = name.replace(/\\/g, '') + for (const [prefix, plugin] of Object.entries(prefixPluginMap)) { if (!name.startsWith(prefix)) continue // The keypath is the part of the variable name after the prefix let keypath = name.slice(prefix.length) - if (keypath.startsWith('-')) keypath = keypath.slice(1) - if (keypath === '') keypath = null + let option = null - return [plugin, keypath] + let optionStart = keypath.indexOf('--') + if (optionStart !== -1) { + option = keypath.slice(optionStart+2) + keypath = keypath.slice(0, optionStart) + } + + if (keypath == '' && option === 'default') { + keypath = 'DEFAULT' + option = null + } else if (keypath.startsWith('-')) { + keypath = keypath.slice(1) + } + + if (keypath === '') { + return [plugin, null, null] + } + + console.log({ + opt: option ? camelize(option) : option, + }) + + return [plugin, keypath, option === null ? null : camelize(option)] } - return [null, null] + return [null, null, null] +} + +/** + * @param {string} str + * @returns {string} + */ +function camelize(str) { + return str.replace(/-([a-zA-Z])/g, (v) => v.slice(1).toUpperCase()) } diff --git a/tests/css-configuration.test.js b/tests/css-configuration.test.js index 9b25c2bbc..5e676de24 100644 --- a/tests/css-configuration.test.js +++ b/tests/css-configuration.test.js @@ -6,8 +6,25 @@ test('it does something', () => { content: [ { raw: html` +
-
+ +
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
`, }, ], @@ -18,22 +35,92 @@ test('it does something', () => { @tailwind utilities; :theme { - --colors-potato: #facade; + --colors: unset; + --colors-mint-50: #f3fdfb; + --colors-mint-900: #043820; + --colors-plum-50: #f8f6fe; + --colors-plum-900: #120c64; + --colors-primary: theme(colors.mint-50); + + --font-family-display: Graphik, sans-serif; + --font-family-display--font-feature-settings: "cv11", "ss01"; + + --font-size-10xl: 10rem; + --font-size-10xl--line-height: 10rem; + + --spacing-1\/4: 25%; + --spacing-1\/2: 50%; + --spacing-3\/4: 75%; + + --shadow--default: 0 3px 5px -2px hsl(220 3% 15% / 4%), 0 7px 14px -5px hsl(220 + 3% 15% / 6%); + + --animation-flash: flash 1s; } `, config ).then((result) => { expect(result.css).toMatchFormattedCss(css` - .text-black { - --tw-text-opacity: 1; - color: rgb(0 0 0 / var(--tw-text-opacity)); + .px-1\/2 { + padding-left: 50%; + padding-right: 50%; } - .text-potato { + .px-1\/4 { + padding-left: 25%; + padding-right: 25%; + } + .px-3\/4 { + padding-left: 75%; + padding-right: 75%; + } + .font-display { + font-feature-settings: "cv11", "ss01"; + font-family: Graphik, sans-serif; + } + .text-10xl { + font-size: 10rem; + line-height: 10rem; + } + .text-mint-50 { --tw-text-opacity: 1; - color: rgb(250 202 222 / var(--tw-text-opacity)); + color: rgb(243 253 251 / var(--tw-text-opacity)); + } + .text-mint-900 { + --tw-text-opacity: 1; + color: rgb(4 56 32 / var(--tw-text-opacity)); + } + .text-plum-50 { + --tw-text-opacity: 1; + color: rgb(248 246 254 / var(--tw-text-opacity)); + } + .text-plum-900 { + --tw-text-opacity: 1; + color: rgb(18 12 100 / var(--tw-text-opacity)); + } + .text-primary { + color: #f3fdfb; + } + .shadow { + --tw-shadow: 0 3px 5px -2px #2526270a, 0 7px 14px -5px #2526270f; + --tw-shadow-colored: 0 3px 5px -2px var(--tw-shadow-color), 0 7px 14px -5px var(--tw-shadow-color); + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), + var(--tw-shadow); } :root { - --colors-potato: #facade; + --colors-mint-50: #f3fdfb; + --colors-mint-900: #043820; + --colors-plum-50: #f8f6fe; + --colors-plum-900: #120c64; + --colors-primary: #f3fdfb; + --font-family-display: Graphik, sans-serif; + --font-family-display--font-feature-settings: "cv11", "ss01"; + --font-size-10xl: 10rem; + --font-size-10xl--line-height: 10rem; + --spacing-1\/4: 25%; + --spacing-1\/2: 50%; + --spacing-3\/4: 75%; + --shadow--default: 0 3px 5px -2px #2526270a, 0 7px 14px -5px #2526270f; + --animation-flash: flash 1s; } `) }) From 4ae6f064664d416ec25986da1c660df902ca39db Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 12:51:01 -0400 Subject: [PATCH 66/85] Refactor a bit --- src/lib/parseCssConfig.js | 47 ++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 25 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 5020cd623..cd907007a 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -10,33 +10,26 @@ export function parseCssConfig(root) { let config = { extend: { colors: {} } } - let theme = root.nodes.find(node => node.type === 'rule' && node.selector === ':theme') - if (!theme) return config + root.each(node => { + if (node.type !== 'rule' || node.selector !== ':theme') return - theme.walkDecls((decl) => { - if (decl.prop.startsWith('--')) { - parseVariable(config, decl) - } else { - // Only CSS variables are allowed in the theme rule - // TODO: Maybe turn this into an error? - decl.remove() - } + node.walkDecls((decl) => { + if (decl.prop.startsWith('--')) { + parseVariable(config, decl) + } else { + // Only CSS variables are allowed in the theme rule + // TODO: Maybe turn this into an error? + decl.remove() + } + }) + + // Allow the variables to be used with var() anywhere in CSS + node.selector = ':root' }) - // Allow the variables to be used with var() anywhere in CSS - theme.selector = ':root' - return config } -let prefixPluginMap = { - 'colors': 'colors', - 'spacing': 'spacing', - 'font-family': 'fontFamily', - 'font-size': 'fontSize', - 'shadow': 'boxShadow', -} - /** * Parse a key into one or more actions that modify the config and/or CSS * @@ -103,6 +96,14 @@ function parseVariable(config, decl) { * @returns {[plugin: string|null, keypath: string|null, option: string|null]} */ function parseVariableName(name) { + const prefixPluginMap = { + 'colors': 'colors', + 'spacing': 'spacing', + 'font-family': 'fontFamily', + 'font-size': 'fontSize', + 'shadow': 'boxShadow', + } + // Unescape the name if needed // This is needed for CSS variables that contain special characters name = name.replace(/\\/g, '') @@ -131,10 +132,6 @@ function parseVariableName(name) { return [plugin, null, null] } - console.log({ - opt: option ? camelize(option) : option, - }) - return [plugin, keypath, option === null ? null : camelize(option)] } From dfb0958147822efc1324b514a89a7523e9d3f1dc Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 13:10:56 -0400 Subject: [PATCH 67/85] wip --- src/lib/parseCssConfig.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index cd907007a..3659c0263 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -52,6 +52,9 @@ function parseVariable(config, decl) { decl.remove() return + } else if (keypath !== null && value === 'unset') { + // when using `--plugin-key: unset` we want to remove that from the config + throw new Error("Not implemented yet") } // When using `--some-plugin: initial` it should reset to the default value for that key @@ -102,6 +105,7 @@ function parseVariableName(name) { 'font-family': 'fontFamily', 'font-size': 'fontSize', 'shadow': 'boxShadow', + 'blur': 'blur', } // Unescape the name if needed From 665569d62680452c2c04c7fb667d38d7c1ede695 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 13:11:05 -0400 Subject: [PATCH 68/85] =?UTF-8?q?Don=E2=80=99t=20break=20tools=20using=20c?= =?UTF-8?q?ustom=20build?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/setupTrackingContext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/setupTrackingContext.js b/src/lib/setupTrackingContext.js index 419dd8594..5bd90701d 100644 --- a/src/lib/setupTrackingContext.js +++ b/src/lib/setupTrackingContext.js @@ -80,7 +80,7 @@ function getTailwindConfig(configOrPath, cssThemeValues) { // Retrieve an existing context from cache if possible (since contexts are unique per // source path), or set up a new one (including setting up watchers and registering // plugins) then return it -export default function setupTrackingContext(configOrPath, cssThemeValues) { +export default function setupTrackingContext(configOrPath, cssThemeValues = {}) { return ({ tailwindDirectives, registerDependency }) => { return (root, result) => { let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = From b57d3d1bc544eb6a12ac15f910730fb4cc0271d4 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 13:38:50 -0400 Subject: [PATCH 69/85] wip --- src/lib/parseCssConfig.js | 41 +++++++++++++++++++++++---------- tests/css-configuration.test.js | 2 +- 2 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 3659c0263..66575db46 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -1,5 +1,7 @@ // @ts-check +import { toPath } from '../util/toPath.js' + /** * Find and convert the `:theme` rule to a configuration object * This is merged with the user's JS config @@ -77,26 +79,35 @@ function parseVariable(config, decl) { // All other cases are config keys in a plugin config.extend[plugin] ??= {} - if (!option) { - config.extend[plugin][keypath] = value - return + let [path, key] = [ + keypath.slice(0, -1), + keypath[keypath.length-1], + ] + + let obj = config.extend[plugin] + let segment + while (segment = path.shift()) { + obj[segment] ??= {} + obj = obj[segment] } - if (!Array.isArray(config.extend[plugin][keypath])) { - config.extend[plugin][keypath] = [ - config.extend[plugin][keypath], - {} - ] - } + if (option) { + // TODO: This is weird + if (!Array.isArray(obj[key])) { + obj[key] = [obj[key], {}] + } - config.extend[plugin][keypath][1][option] = value + obj[key][1][option] = value + } else { + obj[key] = value + } } /** * Parse a key into one or more actions that modify the config and/or CSS * * @param {string} name - * @returns {[plugin: string|null, keypath: string|null, option: string|null]} + * @returns {[plugin: string|null, keypath: string[]|null, option: string|null]} */ function parseVariableName(name) { const prefixPluginMap = { @@ -136,7 +147,13 @@ function parseVariableName(name) { return [plugin, null, null] } - return [plugin, keypath, option === null ? null : camelize(option)] + option = option === null ? null : camelize(option); + + if (plugin === 'colors') { + return [plugin, keypath.split('-'), option] + } + + return [plugin, [keypath], option] } return [null, null, null] diff --git a/tests/css-configuration.test.js b/tests/css-configuration.test.js index 5e676de24..868179383 100644 --- a/tests/css-configuration.test.js +++ b/tests/css-configuration.test.js @@ -40,7 +40,7 @@ test('it does something', () => { --colors-mint-900: #043820; --colors-plum-50: #f8f6fe; --colors-plum-900: #120c64; - --colors-primary: theme(colors.mint-50); + --colors-primary: theme(colors.mint.50); --font-family-display: Graphik, sans-serif; --font-family-display--font-feature-settings: "cv11", "ss01"; From 971253b1cf771cca1af73c6f5ec91a3310784ea8 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 13:40:25 -0400 Subject: [PATCH 70/85] wip --- src/lib/parseCssConfig.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 66575db46..9acc6fd1e 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -1,7 +1,5 @@ // @ts-check -import { toPath } from '../util/toPath.js' - /** * Find and convert the `:theme` rule to a configuration object * This is merged with the user's JS config From 7573cc7d2ab9ad0843ba1682294a88fe30676e0f Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 13:43:44 -0400 Subject: [PATCH 71/85] Fix stuff --- src/lib/setupTrackingContext.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib/setupTrackingContext.js b/src/lib/setupTrackingContext.js index 5bd90701d..ba4d9c228 100644 --- a/src/lib/setupTrackingContext.js +++ b/src/lib/setupTrackingContext.js @@ -28,7 +28,7 @@ function getCandidateFiles(context, tailwindConfig) { } // Get the config object based on a path -function getTailwindConfig(configOrPath, cssThemeValues) { +function getTailwindConfig(configOrPath, cssThemeValues = {}) { let userConfigPath = resolveConfigPath(configOrPath) if (userConfigPath !== null) { @@ -57,7 +57,7 @@ function getTailwindConfig(configOrPath, cssThemeValues) { delete require.cache[file] } let newConfig = validateConfig( - resolveConfig({ theme: cssThemeValues }, loadConfig(userConfigPath)) + resolveConfig(loadConfig(userConfigPath), { theme: cssThemeValues }) ) let newHash = hash(newConfig) configPathCache.set(userConfigPath, [newConfig, newHash, newDeps, newModified]) @@ -66,8 +66,8 @@ function getTailwindConfig(configOrPath, cssThemeValues) { // It's a plain object, not a path let newConfig = resolveConfig( - { theme: cssThemeValues }, - configOrPath?.config ?? configOrPath ?? {} + configOrPath?.config ?? configOrPath ?? {}, + { theme: cssThemeValues } ) newConfig = validateConfig(newConfig) From 67fc3c30e5ecdafcb52929d468271e63153b4186 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 14:03:07 -0400 Subject: [PATCH 72/85] Refactor --- src/lib/parseCssConfig.js | 295 +++++++++++++++++++++----------------- src/plugin.js | 4 +- 2 files changed, 166 insertions(+), 133 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 9acc6fd1e..f5e2beee1 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -1,160 +1,193 @@ // @ts-check -/** - * Find and convert the `:theme` rule to a configuration object - * This is merged with the user's JS config - * It should take precedence over the JS config - * - * @param {import('postcss').Root} root - */ -export function parseCssConfig(root) { - let config = { extend: { colors: {} } } +// config[plugin] = null // Remomve from base config +// config[plugin][key] = null // not supported +// config[plugin] = "anything" // not supported +// config[plugin][key] = "foo" // not supported - root.each(node => { - if (node.type !== 'rule' || node.selector !== ':theme') return +export class CssBasedConfig { + /** @type {*} */ + config = {}; - node.walkDecls((decl) => { - if (decl.prop.startsWith('--')) { - parseVariable(config, decl) - } else { - // Only CSS variables are allowed in the theme rule - // TODO: Maybe turn this into an error? - decl.remove() + /** + * Find and convert the `:theme` rule to a configuration object + * This is merged with the user's JS config + * It should take precedence over the JS config + * + * @param {import('postcss').Root} root + * @returns {*} + */ + parse(root) { + this.config = { extend: {} } + + let rules = this.getThemeRules(root) + + rules.forEach(rule => { + rule.walkDecls((decl) => { + if (decl.prop.startsWith('--')) { + this.parseVariable(decl) + } else { + throw decl.error('Only CSS variables are allowed in `:theme`') + } + }) + + // Allow the variables to be used with var() anywhere in CSS + rule.selector = ':root' + }) + + return this.config + } + + /** + * Walk the tree and find all `:theme` rules + * + * @param {import('postcss').Root} root + * @returns {import('postcss').Rule[]} + */ + getThemeRules(root) { + let rules = [] + + root.each(node => { + if (node.type === 'rule' && node.selector === ':theme') { + rules.push(node) } }) - // Allow the variables to be used with var() anywhere in CSS - node.selector = ':root' - }) - - return config -} - -/** - * Parse a key into one or more actions that modify the config and/or CSS - * - * @param {*} config - * @param {import('postcss').Declaration} decl - */ -function parseVariable(config, decl) { - // Parse the variable name into a config plugin and keypath - let [name, value] = [decl.prop.slice(2), decl.value] - let [plugin, keypath, option] = parseVariableName(name) - - // We couldn't find a plugin for this variable, so we can't do anything with it - if (plugin === null) return - - if (keypath === null && value === 'unset') { - // when using `--some-plugin: unset` we want to reset whatever the default value is - config[plugin] = {} - - // This also means there is no reason to keep the variable in the CSS - decl.remove() - - return - } else if (keypath !== null && value === 'unset') { - // when using `--plugin-key: unset` we want to remove that from the config - throw new Error("Not implemented yet") + return rules } - // When using `--some-plugin: initial` it should reset to the default value for that key - // This effectively means removing it - if (keypath === null && value === 'initial') { - delete config[plugin] - delete config.extend[plugin] + /** + * Parse a variable declaration and modify the config + * + * @param {import('postcss').Declaration} decl + */ + parseVariable(decl) { + let config = this.config - // This also means there is no reason to keep the variable in the CSS - decl.remove() + // Parse the variable name into a config plugin and keypath + let [name, value] = [decl.prop.slice(2), decl.value] + let [plugin, keypath, option] = this.parseVariableName(name) - return - } + // We couldn't find a plugin for this variable, so we can't do anything with it + if (plugin === null) return - // TODO: Can this happen - if (keypath === null) { - return - } + if (keypath === null && value === 'unset') { + // when using `--some-plugin: unset` we want to reset whatever the default value is + config[plugin] = {} - // All other cases are config keys in a plugin - config.extend[plugin] ??= {} + // This also means there is no reason to keep the variable in the CSS + decl.remove() - let [path, key] = [ - keypath.slice(0, -1), - keypath[keypath.length-1], - ] - - let obj = config.extend[plugin] - let segment - while (segment = path.shift()) { - obj[segment] ??= {} - obj = obj[segment] - } - - if (option) { - // TODO: This is weird - if (!Array.isArray(obj[key])) { - obj[key] = [obj[key], {}] + return + } else if (keypath !== null && value === 'unset') { + // when using `--plugin-key: unset` we want to remove that from the config + throw new Error("Not implemented yet") } - obj[key][1][option] = value - } else { - obj[key] = value - } -} + // When using `--some-plugin: initial` it should reset to the default value for that key + // This effectively means removing it + if (keypath === null && value === 'initial') { + delete config[plugin] + delete config.extend[plugin] -/** - * Parse a key into one or more actions that modify the config and/or CSS - * - * @param {string} name - * @returns {[plugin: string|null, keypath: string[]|null, option: string|null]} - */ -function parseVariableName(name) { - const prefixPluginMap = { - 'colors': 'colors', - 'spacing': 'spacing', - 'font-family': 'fontFamily', - 'font-size': 'fontSize', - 'shadow': 'boxShadow', - 'blur': 'blur', + // This also means there is no reason to keep the variable in the CSS + decl.remove() + + return + } + + // TODO: Can this happen + if (keypath === null) { + return + } + + // All other cases are config keys in a plugin + config.extend[plugin] ??= {} + + let [path, key] = [ + keypath.slice(0, -1), + keypath[keypath.length-1], + ] + + let obj = config.extend[plugin] + let segment + while (segment = path.shift()) { + obj[segment] ??= {} + obj = obj[segment] + } + + if (option) { + // TODO: This is weird + if (!Array.isArray(obj[key])) { + obj[key] = [obj[key], {}] + } + + obj[key][1][option] = value + } else { + obj[key] = value + } } - // Unescape the name if needed - // This is needed for CSS variables that contain special characters - name = name.replace(/\\/g, '') + /** + * Convert a variable name into: + * - The associated plugin + * - A keypath to modify inside plugin's config (if available) + * - An "option" which is a key into the "options" object when a Tuple-like value is used + * + * @param {string} name + * @returns {[plugin: string|null, keypath: string[]|null, option: string|null]} + */ + parseVariableName(name) { + // Unescape the name if needed + // This is needed for CSS variables that contain special characters + name = name.replace(/\\/g, '') - for (const [prefix, plugin] of Object.entries(prefixPluginMap)) { - if (!name.startsWith(prefix)) continue + for (const [prefix, plugin] of Object.entries(this.prefixPluginMap)) { + if (!name.startsWith(prefix)) continue - // The keypath is the part of the variable name after the prefix - let keypath = name.slice(prefix.length) - let option = null + // The keypath is the part of the variable name after the prefix + let keypath = name.slice(prefix.length) + let option = null - let optionStart = keypath.indexOf('--') - if (optionStart !== -1) { - option = keypath.slice(optionStart+2) - keypath = keypath.slice(0, optionStart) + let optionStart = keypath.indexOf('--') + if (optionStart !== -1) { + option = keypath.slice(optionStart+2) + keypath = keypath.slice(0, optionStart) + } + + if (keypath == '' && option === 'default') { + keypath = 'DEFAULT' + option = null + } else if (keypath.startsWith('-')) { + keypath = keypath.slice(1) + } + + if (keypath === '') { + return [plugin, null, null] + } + + option = option === null ? null : camelize(option); + + if (plugin === 'colors') { + return [plugin, keypath.split('-'), option] + } + + return [plugin, [keypath], option] } - if (keypath == '' && option === 'default') { - keypath = 'DEFAULT' - option = null - } else if (keypath.startsWith('-')) { - keypath = keypath.slice(1) - } - - if (keypath === '') { - return [plugin, null, null] - } - - option = option === null ? null : camelize(option); - - if (plugin === 'colors') { - return [plugin, keypath.split('-'), option] - } - - return [plugin, [keypath], option] + return [null, null, null] } - return [null, null, null] + get prefixPluginMap() { + return { + 'colors': 'colors', + 'spacing': 'spacing', + 'font-family': 'fontFamily', + 'font-size': 'fontSize', + 'shadow': 'boxShadow', + 'blur': 'blur', + } + } } /** diff --git a/src/plugin.js b/src/plugin.js index 396f9b54c..fb53e43bb 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -6,7 +6,7 @@ import processTailwindFeatures from './processTailwindFeatures' import { env } from './lib/sharedState' import { findAtConfigPath } from './lib/findAtConfigPath' import { handleImportAtRules } from './lib/handleImportAtRules' -import { parseCssConfig } from './lib/parseCssConfig' +import { CssBasedConfig } from './lib/parseCssConfig' module.exports = function tailwindcss(configOrPath) { return { @@ -25,7 +25,7 @@ module.exports = function tailwindcss(configOrPath) { configOrPath = findAtConfigPath(root, result) ?? configOrPath // Parse any CSS-based config values from `:theme` rules - let themeValues = parseCssConfig(root) + let themeValues = new CssBasedConfig().parse(root) let context = setupTrackingContext(configOrPath, themeValues) From e83435295d76ea4243988c54a56cb3427e187e56 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 14:04:25 -0400 Subject: [PATCH 73/85] Simplify --- src/lib/parseCssConfig.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index f5e2beee1..9f9d01617 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -24,11 +24,11 @@ export class CssBasedConfig { rules.forEach(rule => { rule.walkDecls((decl) => { - if (decl.prop.startsWith('--')) { - this.parseVariable(decl) - } else { + if (!decl.prop.startsWith('--')) { throw decl.error('Only CSS variables are allowed in `:theme`') } + + this.parseVariable(decl) }) // Allow the variables to be used with var() anywhere in CSS @@ -45,13 +45,8 @@ export class CssBasedConfig { * @returns {import('postcss').Rule[]} */ getThemeRules(root) { - let rules = [] - - root.each(node => { - if (node.type === 'rule' && node.selector === ':theme') { - rules.push(node) - } - }) + /** @type {any[]} */ + let rules = root.nodes.filter(node => node.type === 'rule' && node.selector === ':theme') return rules } From bf583334a22a1d0babd760c04889570c913e6857 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 14:08:05 -0400 Subject: [PATCH 74/85] wip --- src/lib/parseCssConfig.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 9f9d01617..c9ab95c49 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -5,6 +5,10 @@ // config[plugin] = "anything" // not supported // config[plugin][key] = "foo" // not supported +/** + * @typedef {[plugin: string|null, key: string[]|null, option: string|null]} ConfigPath + */ + export class CssBasedConfig { /** @type {*} */ config = {}; @@ -130,7 +134,7 @@ export class CssBasedConfig { * - An "option" which is a key into the "options" object when a Tuple-like value is used * * @param {string} name - * @returns {[plugin: string|null, keypath: string[]|null, option: string|null]} + * @returns {ConfigPath} */ parseVariableName(name) { // Unescape the name if needed From 526276cb97040c1f46e34044cbf831f479d93e10 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 14:15:22 -0400 Subject: [PATCH 75/85] wip --- src/lib/parseCssConfig.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index c9ab95c49..762df645b 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -67,8 +67,12 @@ export class CssBasedConfig { let [name, value] = [decl.prop.slice(2), decl.value] let [plugin, keypath, option] = this.parseVariableName(name) - // We couldn't find a plugin for this variable, so we can't do anything with it - if (plugin === null) return + if (plugin === null) { + // We couldn't find a plugin for this variable, so we can't do anything with it + // This also means there is no reason to keep the variable in the CSS + decl.remove() + return + } if (keypath === null && value === 'unset') { // when using `--some-plugin: unset` we want to reset whatever the default value is @@ -78,21 +82,11 @@ export class CssBasedConfig { decl.remove() return - } else if (keypath !== null && value === 'unset') { - // when using `--plugin-key: unset` we want to remove that from the config - throw new Error("Not implemented yet") } - // When using `--some-plugin: initial` it should reset to the default value for that key - // This effectively means removing it - if (keypath === null && value === 'initial') { - delete config[plugin] - delete config.extend[plugin] - - // This also means there is no reason to keep the variable in the CSS - decl.remove() - - return + if (keypath !== null && value === 'unset') { + // when using `--plugin-key: unset` we want to remove that from the config + throw decl.error("Not implemented yet"); } // TODO: Can this happen From a347719dc8ebc2624f3dfe48a881456bc8e9c4b8 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 14 Jun 2023 14:16:44 -0400 Subject: [PATCH 76/85] wip --- src/lib/parseCssConfig.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 762df645b..335c87773 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -1,10 +1,5 @@ // @ts-check -// config[plugin] = null // Remomve from base config -// config[plugin][key] = null // not supported -// config[plugin] = "anything" // not supported -// config[plugin][key] = "foo" // not supported - /** * @typedef {[plugin: string|null, key: string[]|null, option: string|null]} ConfigPath */ @@ -172,6 +167,8 @@ export class CssBasedConfig { } get prefixPluginMap() { + // TODO: Maybe build this based on a list of registered plugins + // Or maybe a plugin can register namespaces themselves? return { 'colors': 'colors', 'spacing': 'spacing', From 42699086c3859f70f255db39952c44e21b5dd346 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 15 Jun 2023 09:24:19 -0400 Subject: [PATCH 77/85] Fix test --- src/lib/parseCssConfig.js | 1 + tests/css-configuration.test.js | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 335c87773..81c737e7d 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -170,6 +170,7 @@ export class CssBasedConfig { // TODO: Maybe build this based on a list of registered plugins // Or maybe a plugin can register namespaces themselves? return { + 'animation': 'animation', 'colors': 'colors', 'spacing': 'spacing', 'font-family': 'fontFamily', diff --git a/tests/css-configuration.test.js b/tests/css-configuration.test.js index 868179383..64d452bf7 100644 --- a/tests/css-configuration.test.js +++ b/tests/css-configuration.test.js @@ -61,6 +61,9 @@ test('it does something', () => { config ).then((result) => { expect(result.css).toMatchFormattedCss(css` + .animate-flash { + animation: 1s flash; + } .px-1\/2 { padding-left: 50%; padding-right: 50%; From d88fd1e6e7b988cac452ab5bdc640fbaadb3ec68 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 15 Jun 2023 09:25:24 -0400 Subject: [PATCH 78/85] Do proper CSS unescaping for variables --- src/lib/parseCssConfig.js | 16 +++++++++++++++- tests/css-configuration.test.js | 7 +++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 81c737e7d..fbef1387d 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -128,7 +128,7 @@ export class CssBasedConfig { parseVariableName(name) { // Unescape the name if needed // This is needed for CSS variables that contain special characters - name = name.replace(/\\/g, '') + name = unescape(name) for (const [prefix, plugin] of Object.entries(this.prefixPluginMap)) { if (!name.startsWith(prefix)) continue @@ -188,3 +188,17 @@ export class CssBasedConfig { function camelize(str) { return str.replace(/-([a-zA-Z])/g, (v) => v.slice(1).toUpperCase()) } + +/** + * @param {string} str + * @returns {string} + */ +function unescape(str) { + let pattern = /\\([0-9a-fA-F]{1,6}[\t\n\f\r ]?|[\S\s])/g + + return str.replace(pattern, (match) => + match.length > 2 + ? String.fromCodePoint(parseInt(match.slice(1).trimEnd(), 16)) + : match[1] + ) +} diff --git a/tests/css-configuration.test.js b/tests/css-configuration.test.js index 64d452bf7..76803bdc8 100644 --- a/tests/css-configuration.test.js +++ b/tests/css-configuration.test.js @@ -23,6 +23,7 @@ test('it does something', () => {
+
`, @@ -51,6 +52,7 @@ test('it does something', () => { --spacing-1\/4: 25%; --spacing-1\/2: 50%; --spacing-3\/4: 75%; + --spacing-\32 xl: 20rem; --shadow--default: 0 3px 5px -2px hsl(220 3% 15% / 4%), 0 7px 14px -5px hsl(220 3% 15% / 6%); @@ -72,6 +74,10 @@ test('it does something', () => { padding-left: 25%; padding-right: 25%; } + .px-2xl { + padding-left: 20rem; + padding-right: 20rem; + } .px-3\/4 { padding-left: 75%; padding-right: 75%; @@ -122,6 +128,7 @@ test('it does something', () => { --spacing-1\/4: 25%; --spacing-1\/2: 50%; --spacing-3\/4: 75%; + --spacing-2xl: 20rem; --shadow--default: 0 3px 5px -2px #2526270a, 0 7px 14px -5px #2526270f; --animation-flash: flash 1s; } From ed7c448441f4b8cef25f9a215dff5328d1414dd0 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 15 Jun 2023 12:13:05 -0400 Subject: [PATCH 79/85] Push CSS-based theme resolution inside getTailwindConfig --- src/lib/parseCssConfig.js | 5 +++-- src/lib/setupTrackingContext.js | 6 +++++- src/plugin.js | 5 +---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index fbef1387d..36921ebc7 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -5,8 +5,9 @@ */ export class CssBasedConfig { - /** @type {*} */ - config = {}; + constructor() { + this.config = {} + } /** * Find and convert the `:theme` rule to a configuration object diff --git a/src/lib/setupTrackingContext.js b/src/lib/setupTrackingContext.js index ba4d9c228..550914be0 100644 --- a/src/lib/setupTrackingContext.js +++ b/src/lib/setupTrackingContext.js @@ -12,6 +12,7 @@ import { validateConfig } from '../util/validateConfig.js' import { parseCandidateFiles, resolvedChangedContent } from './content.js' import { loadConfig } from '../lib/load-config' import getModuleDependencies from './getModuleDependencies' +import { CssBasedConfig } from './parseCssConfig.js' let configPathCache = new LRU({ maxSize: 100 }) @@ -80,9 +81,12 @@ function getTailwindConfig(configOrPath, cssThemeValues = {}) { // Retrieve an existing context from cache if possible (since contexts are unique per // source path), or set up a new one (including setting up watchers and registering // plugins) then return it -export default function setupTrackingContext(configOrPath, cssThemeValues = {}) { +export default function setupTrackingContext(configOrPath) { return ({ tailwindDirectives, registerDependency }) => { return (root, result) => { + // Parse any CSS-based config values from `:theme` rules + let cssThemeValues = new CssBasedConfig().parse(root) + let [tailwindConfig, userConfigPath, tailwindConfigHash, configDependencies] = getTailwindConfig(configOrPath, cssThemeValues) diff --git a/src/plugin.js b/src/plugin.js index fb53e43bb..4fcb058f3 100644 --- a/src/plugin.js +++ b/src/plugin.js @@ -24,10 +24,7 @@ module.exports = function tailwindcss(configOrPath) { // path for the file being processed configOrPath = findAtConfigPath(root, result) ?? configOrPath - // Parse any CSS-based config values from `:theme` rules - let themeValues = new CssBasedConfig().parse(root) - - let context = setupTrackingContext(configOrPath, themeValues) + let context = setupTrackingContext(configOrPath) if (root.type === 'document') { let roots = root.nodes.filter((node) => node.type === 'root') From d58afc60d2b494dc457c3a278c979f8c842a57a6 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 19 Jun 2023 17:35:08 -0400 Subject: [PATCH 80/85] Support CSS-based config in the CLI --- src/cli/build/plugin.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/cli/build/plugin.js b/src/cli/build/plugin.js index 89bcbe95f..6b40f13c3 100644 --- a/src/cli/build/plugin.js +++ b/src/cli/build/plugin.js @@ -25,6 +25,7 @@ import getModuleDependencies from '../../lib/getModuleDependencies' import { validateConfig } from '../../util/validateConfig' import { handleImportAtRules } from '../../lib/handleImportAtRules' import { flagEnabled } from '../../featureFlags' +import { CssBasedConfig } from '../../lib/parseCssConfig.js' async function lightningcss(result, { map = true, minify = true } = {}) { try { @@ -156,7 +157,7 @@ let state = { } }, - loadConfig(configPath, content) { + loadConfig(configPath, content, cssThemeValues) { if (this.watcher && configPath) { this.refreshConfigDependencies() } @@ -173,7 +174,7 @@ let state = { }, } - this.configBag.config = validateConfig(resolveConfig(this.configBag.config)) + this.configBag.config = validateConfig(resolveConfig(this.configBag.config, { theme: cssThemeValues })) // Override content files if `--content` has been passed explicitly if (content?.length > 0) { @@ -222,7 +223,7 @@ let state = { return content }, - getContext({ createContext, cliConfigPath, root, result, content }) { + getContext({ createContext, cliConfigPath, root, result, content, cssThemeValues }) { if (this.context) { this.context.changedContent = this.changedContent.splice(0) @@ -234,7 +235,7 @@ let state = { env.DEBUG && console.timeEnd('Searching for config') env.DEBUG && console.time('Loading config') - let config = this.loadConfig(configPath, content) + let config = this.loadConfig(configPath, content, cssThemeValues) env.DEBUG && console.timeEnd('Loading config') env.DEBUG && console.time('Creating context') @@ -291,6 +292,9 @@ export async function createProcessor(args, cliConfigPath) { return { postcssPlugin: 'tailwindcss', Once(root, { result }) { + // Parse any CSS-based config values from `:theme` rules + let cssThemeValues = new CssBasedConfig().parse(root) + env.DEBUG && console.time('Compiling CSS') tailwind(({ createContext }) => { console.error() @@ -303,6 +307,7 @@ export async function createProcessor(args, cliConfigPath) { root, result, content, + cssThemeValues, }) } })(root, result) From cb4fd4fcec4eb59a5eff5b0c88d1753e893ca4e7 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 19 Jun 2023 17:18:47 -0400 Subject: [PATCH 81/85] hardocde oxide version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7fb3d7c30..fe19047d0 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ }, "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/oxide": "file:oxide/crates/node", + "@tailwindcss/oxide": "0.0.0-insiders.776d5bf", "arg": "^5.0.2", "browserslist": "^4.21.7", "chokidar": "^3.5.3", From 1797de20427a348703c8b28b48607e601a6721e0 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 19 Jun 2023 17:18:27 -0400 Subject: [PATCH 82/85] do not alias shadow to box-shadow --- src/lib/parseCssConfig.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/parseCssConfig.js b/src/lib/parseCssConfig.js index 36921ebc7..624fa7030 100644 --- a/src/lib/parseCssConfig.js +++ b/src/lib/parseCssConfig.js @@ -176,7 +176,7 @@ export class CssBasedConfig { 'spacing': 'spacing', 'font-family': 'fontFamily', 'font-size': 'fontSize', - 'shadow': 'boxShadow', + // 'shadow': 'boxShadow', 'blur': 'blur', } } From ad014a2ec45933998f7c56fbcf7fa38abf51525c Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 19 Jun 2023 18:50:01 -0400 Subject: [PATCH 83/85] disableColorOpacityUtilitiesByDefault but true --- src/featureFlags.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/featureFlags.js b/src/featureFlags.js index 59cc48509..c594bd969 100644 --- a/src/featureFlags.js +++ b/src/featureFlags.js @@ -3,7 +3,7 @@ import log from './util/log' let defaults = { optimizeUniversalDefaults: false, - disableColorOpacityUtilitiesByDefault: false, + disableColorOpacityUtilitiesByDefault: true, relativeContentPathsByDefault: false, oxideParser: true, logicalSiblingUtilities: false, From 54ce83bb86a0aba3632fbf7b33f5bb0cd9c4b219 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 19 Jun 2023 19:58:12 -0400 Subject: [PATCH 84/85] drop detect nesting --- src/processTailwindFeatures.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/processTailwindFeatures.js b/src/processTailwindFeatures.js index 952e17a13..7fac4272f 100644 --- a/src/processTailwindFeatures.js +++ b/src/processTailwindFeatures.js @@ -7,7 +7,7 @@ import resolveDefaultsAtRules from './lib/resolveDefaultsAtRules' import collapseAdjacentRules from './lib/collapseAdjacentRules' import collapseDuplicateDeclarations from './lib/collapseDuplicateDeclarations' import partitionApplyAtRules from './lib/partitionApplyAtRules' -import detectNesting from './lib/detectNesting' +// import detectNesting from './lib/detectNesting' import { createContext } from './lib/setupContextUtils' import { issueFlagNotices } from './featureFlags' @@ -15,7 +15,7 @@ export default function processTailwindFeatures(setupContext) { return function (root, result) { let { tailwindDirectives, applyDirectives } = normalizeTailwindDirectives(root) - detectNesting()(root, result) + // detectNesting()(root, result) // Partition apply rules that are found in the css // itself. From eb7ba4f44ae062e57795ff7e7cb6151c012448fe Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Mon, 19 Jun 2023 19:58:25 -0400 Subject: [PATCH 85/85] bump experimental version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fe19047d0..34db0a775 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "tailwindcss", - "version": "3.3.2", + "version": "0.0.0-experimental.4", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "main": "lib/index.js",