tailwindcss/tests/util/source-maps.js
Robin Malfait 8e60a3c7e8
Use Lightning CSS in the PostCSS Plugin (#10399)
* bump lightningcss

* use `lightningcss` in the main PostCss Plugin

* use lightningcss in our custom matchers

Now that we are using `lightningcss` and nesting in the new `oxide`
engine, the generated output _will_ be different in the majority of test
cases.

Using a combination of `prettier` and `lightningcss` will make the
output consistent.

The moment we are fully using the `oxide` engine, we can drop
`lightningcss` or `prettier` again to improve the performance of the
tests.

* update tests to apply `lightningcss` related changes

* update changelog

* add `lightningcss` and `browserslist` as dev dependencies to stable package.json

* only use `lightningcss` in tests (without prettier)

We will only fallback to prettier if lightningcss fails somehow.

* apply side effect chagnes due to only using lightningcss for tests

* make CI happy (integration tests)

Apply changes to integration tests now that we are using lightningcss

* transform `lightningcss` for Node 12 when running tests

* run prettier on failing tests for `toMatchFormattedCss`

This will result in better diffs because diffs are typically per block
and/or per line. But lightningcss will simplify certain selectors and
the diff won't be as clear.

We will only apply the prettier formatting for failing tests in the diff
view so that diffs are cleaner and we don't pay for the additional
prettier calls when tests pass.
2023-01-23 20:44:31 +01:00

80 lines
2.2 KiB
JavaScript

import { SourceMapConsumer } from 'source-map-js'
/**
* Parse the source maps from a PostCSS result
*
* @param {import('postcss').Result} result
*/
export function parseSourceMaps(result) {
let map = result.map.toJSON()
return {
sources: map.sources,
annotations: annotatedMappings(map),
}
}
/**
* An 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
* lines are mapped back to the original source
*
* Including when using @apply with multiple classes
*
* @param {import('source-map-js').RawSourceMap} map
*/
function annotatedMappings(map) {
const smc = new SourceMapConsumer(map)
const annotations = {}
smc.eachMapping((mapping) => {
let annotation = (annotations[mapping.generatedLine] = annotations[mapping.generatedLine] || {
...mapping,
original: {
start: [mapping.originalLine, mapping.originalColumn],
end: [mapping.originalLine, mapping.originalColumn],
},
generated: {
start: [mapping.generatedLine, mapping.generatedColumn],
end: [mapping.generatedLine, mapping.generatedColumn],
},
})
annotation.generated.end[0] = mapping.generatedLine
annotation.generated.end[1] = mapping.generatedColumn
annotation.original.end[0] = mapping.originalLine
annotation.original.end[1] = mapping.originalColumn
})
return Object.values(annotations).map((annotation) => {
return `${formatRange(annotation.original)} -> ${formatRange(annotation.generated)}`
})
}
/**
* @param {object} range
* @param {[number, number]} range.start
* @param {[number, number]} range.end
*/
function formatRange(range) {
if (range.start[0] === range.end[0]) {
// This range is on the same line
// and the columns are the same
if (range.start[1] === range.end[1]) {
return `${range.start[0]}:${range.start[1]}`
}
// This range is on the same line
// but the columns are different
return `${range.start[0]}:${range.start[1]}-${range.end[1]}`
}
// This range spans multiple lines
return `${range.start[0]}:${range.start[1]}-${range.end[0]}:${range.end[1]}`
}