From 352c563d991f10f2cbf455d1dda999b00f5e86bd Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Wed, 31 May 2023 18:28:11 +0200 Subject: [PATCH] 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