index.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. 'use strict'
  2. var slugify = require('slugify')
  3. var escaper = require('escaper')
  4. var stripComments = require('strip-css-comments')
  5. module.exports = scope
  6. scope.replace = replace
  7. function scope (css, parent, o) {
  8. if (!css) return css
  9. if (!parent) return css
  10. if (typeof o === 'string') o = {keyframes: o}
  11. if (!o) o = {keyframes: false}
  12. css = replace(css, parent + ' $1$2')
  13. //regexp.escape
  14. var parentRe = parent.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
  15. //replace self-selectors
  16. css = css.replace(new RegExp('(' + parentRe + ')\\s*\\1(?=[\\s\\r\\n,{])', 'g'), '$1')
  17. //replace `:host` with parent
  18. css = css.replace(new RegExp('(' + parentRe + ')\\s*:host', 'g'), '$1')
  19. //revoke wrongly replaced @ statements, like @supports, @import, @media etc.
  20. css = css.replace(new RegExp('(' + parentRe + ')\\s*@', 'g'), '@')
  21. //revoke wrongly replaced :root blocks
  22. css = css.replace(new RegExp('(' + parentRe + ')\\s*:root', 'g'), ':root')
  23. //animations: prefix animation anmes
  24. var animations = [],
  25. animationNameRe = /@keyframes\s+([a-zA-Z0-9_-]+)\s*{/g,
  26. match
  27. while ((match = animationNameRe.exec(css)) !== null) {
  28. if (animations.indexOf(match[1]) < 0)
  29. animations.push(match[1])
  30. }
  31. var slug = slugify(parent)
  32. animations.forEach(function (name) {
  33. var newName = (o.keyframes === true ? slug + '-' : typeof o.keyframes === 'string' ? o.keyframes : '') + name
  34. css = css.replace(new RegExp('(@keyframes\\s+)' + name + '(\\s*{)', 'g'),
  35. '$1' + newName + '$2')
  36. css = css.replace(new RegExp('(animation(?:-name)?\\s*:[^;]*\\s*)' + name + '([\\s;}])', 'g'),
  37. '$1' + newName + '$2')
  38. })
  39. //animation: revoke wrongly replaced keyframes
  40. css = css.replace(new RegExp('(' + parentRe + ' )(\\s*(?:to|from|[+-]?(?:(?:\\.\\d+)|(?:\\d+(?:\\.\\d*)?))%))(?=[\\s\\r\\n,{])', 'g'), '$2')
  41. return css
  42. }
  43. function replace (css, replacer) {
  44. var arr = []
  45. css = stripComments(css)
  46. // escape strings etc.
  47. css = escaper.replace(css, true, arr)
  48. css = css.replace(/([^\r\n,{}]+)(,(?=[^}]*{)|\s*{)/g, replacer)
  49. // insert comments, strings etc. back
  50. css = escaper.paste(css, arr)
  51. return css
  52. }