source-maps.js 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { SourceMapConsumer } from 'source-map-js'
  2. /**
  3. * Parse the source maps from a PostCSS result
  4. *
  5. * @param {import('postcss').Result} result
  6. */
  7. export function parseSourceMaps(result) {
  8. const map = result.map.toJSON()
  9. return {
  10. sources: map.sources,
  11. annotations: annotatedMappings(map),
  12. }
  13. }
  14. /**
  15. * An string annotation that represents a source map
  16. *
  17. * It's not meant to be exhaustive just enough to
  18. * verify that the source map is working and that
  19. * lines are mapped back to the original source
  20. *
  21. * Including when using @apply with multiple classes
  22. *
  23. * @param {import('source-map-js').RawSourceMap} map
  24. */
  25. function annotatedMappings(map) {
  26. const smc = new SourceMapConsumer(map)
  27. const annotations = {}
  28. smc.eachMapping((mapping) => {
  29. let annotation = (annotations[mapping.generatedLine] = annotations[mapping.generatedLine] || {
  30. ...mapping,
  31. original: {
  32. start: [mapping.originalLine, mapping.originalColumn],
  33. end: [mapping.originalLine, mapping.originalColumn],
  34. },
  35. generated: {
  36. start: [mapping.generatedLine, mapping.generatedColumn],
  37. end: [mapping.generatedLine, mapping.generatedColumn],
  38. },
  39. })
  40. annotation.generated.end[0] = mapping.generatedLine
  41. annotation.generated.end[1] = mapping.generatedColumn
  42. annotation.original.end[0] = mapping.originalLine
  43. annotation.original.end[1] = mapping.originalColumn
  44. })
  45. return Object.values(annotations).map((annotation) => {
  46. return `${formatRange(annotation.original)} -> ${formatRange(annotation.generated)}`
  47. })
  48. }
  49. /**
  50. * @param {object} range
  51. * @param {[number, number]} range.start
  52. * @param {[number, number]} range.end
  53. */
  54. function formatRange(range) {
  55. if (range.start[0] === range.end[0]) {
  56. // This range is on the same line
  57. // and the columns are the same
  58. if (range.start[1] === range.end[1]) {
  59. return `${range.start[0]}:${range.start[1]}`
  60. }
  61. // This range is on the same line
  62. // but the columns are different
  63. return `${range.start[0]}:${range.start[1]}-${range.end[1]}`
  64. }
  65. // This range spans multiple lines
  66. return `${range.start[0]}:${range.start[1]}-${range.end[0]}:${range.end[1]}`
  67. }