{"version":3,"file":"index.mjs","sources":["../../src/index.js"],"sourcesContent":["/**\n * A style serializer for Stiches. Hopefully we can replace this with\n * an official one in the future.\n */\nimport * as css from 'css'\nimport chalk from 'chalk'\n\n//\n// Utils\nconst flatMap = (arr, iteratee) => [].concat(...arr.map(iteratee))\n\nexport const RULE_TYPES = {\n  media: 'media',\n  rule: 'rule',\n}\n\nconst getClassNames = (selectors, classes) => {\n  return classes ? selectors.concat(classes.split(' ')) : selectors\n}\n\nconst getClassNamesFromTestRenderer = (selectors, {props}) =>\n  getClassNames(\n    selectors,\n    props ? (props.className || props.class || '').toString() : null\n  )\n\nconst shouldDive = (node) =>\n  typeof node.dive === 'function' && typeof node.type() !== 'string'\n\nconst isTagWithClassName = (node) =>\n  node.prop('className') && typeof node.type() === 'string'\n\nconst getClassNamesFromEnzyme = (selectors, node) => {\n  // We need to dive if we have selected a styled child from a shallow render\n  const actualComponent = shouldDive(node) ? node.dive() : node\n  // Find the first node with a className prop\n  const components = actualComponent.findWhere(isTagWithClassName)\n  const classes =\n    components.length && components.first().prop('className')\n      ? components.first().prop('className').toString()\n      : components.first().prop('className')\n\n  return getClassNames(selectors, classes)\n}\n\nconst getClassNamesFromCheerio = (selectors, node) => {\n  const classes = node.attr('class')\n  return getClassNames(selectors, classes)\n}\n\nconst getClassNamesFromDOMElement = (selectors, node) =>\n  getClassNames(selectors, node.getAttribute('class'))\n\nexport const isReactElement = (val) => {\n  if (val.$$typeof === Symbol.for('react.test.json')) {\n    return true\n  } else if (\n    val.hasOwnProperty('props') &&\n    val.hasOwnProperty('type') &&\n    val.hasOwnProperty('ref') &&\n    val.hasOwnProperty('key')\n  ) {\n    // Preact X\n    try {\n      val.$$typeof = Symbol.for('react.test.json')\n      // eslint-disable-next-line no-empty\n    } catch (err) {}\n    return true\n  }\n}\n\nconst domElementPattern = /^((HTML|SVG)\\w*)?Element$/\n\nexport const isDOMElement = (val) =>\n  val.nodeType === 1 &&\n  val.constructor &&\n  val.constructor.name &&\n  domElementPattern.test(val.constructor.name)\n\nconst isEnzymeElement = (val) => typeof val.findWhere === 'function'\nconst isCheerioElement = (val) => val.cheerio === '[cheerio object]'\n\nexport const getClassNamesFromNodes = (nodes) =>\n  nodes.reduce((selectors, node) => {\n    if (isReactElement(node)) {\n      return getClassNamesFromTestRenderer(selectors, node)\n    } else if (isEnzymeElement(node)) {\n      return getClassNamesFromEnzyme(selectors, node)\n    } else if (isCheerioElement(node)) {\n      return getClassNamesFromCheerio(selectors, node)\n    }\n\n    return getClassNamesFromDOMElement(selectors, node)\n  }, [])\n\nlet keyframesPattern = /^@keyframes\\s+(animation-[^{\\s]+)+/\n\nlet removeCommentPattern = /\\/\\*[\\s\\S]*?\\*\\//g\n\nconst getElementRules = (element) => {\n  const nonSpeedyRule = element.textContent\n  if (nonSpeedyRule) {\n    return [nonSpeedyRule]\n  }\n  if (!element.sheet) {\n    return []\n  }\n  // $FlowFixMe - flow doesn't know about `cssRules` property\n  return [].slice.call(element.sheet.cssRules).map((cssRule) => cssRule.cssText)\n}\n\nexport const getStylesFromClassNames = (classNames, elements) => {\n  if (!classNames.length) {\n    return ''\n  }\n\n  let selectorPattern = new RegExp('\\\\.(' + classNames.join('|') + ')')\n  let keyframes = {}\n  let styles = ''\n\n  flatMap(elements, getElementRules).forEach((rule) => {\n    if (selectorPattern.test(rule)) {\n      styles += rule\n    }\n    let match = rule.match(keyframesPattern)\n    if (match !== null) {\n      let name = match[1]\n      if (keyframes[name] === undefined) {\n        keyframes[name] = ''\n      }\n      keyframes[name] += rule\n    }\n  })\n  let keyframeNameKeys = Object.keys(keyframes)\n  let keyframesStyles = ''\n\n  if (keyframeNameKeys.length) {\n    let keyframesNamePattern = new RegExp(keyframeNameKeys.join('|'), 'g')\n    let keyframesNameCache = {}\n    let index = 0\n\n    styles = styles.replace(keyframesNamePattern, (name) => {\n      if (keyframesNameCache[name] === undefined) {\n        keyframesNameCache[name] = `animation-${index++}`\n        keyframesStyles += keyframes[name]\n      }\n      return keyframesNameCache[name]\n    })\n\n    keyframesStyles = keyframesStyles.replace(keyframesNamePattern, (value) => {\n      return keyframesNameCache[value]\n    })\n  }\n\n  return (keyframesStyles + styles).replace(removeCommentPattern, '')\n}\n\nexport const getStyleElements = () =>\n  Array.from(document.querySelectorAll('style'))\n\nlet unique = (arr) => Array.from(new Set(arr))\n\nexport const getKeys = (elements) => unique(elements.filter(Boolean))\n\nexport const hasClassNames = (classNames, selectors, target) =>\n  selectors.some((selector) => {\n    // if no target, use className of the specific css rule and try to find it\n    // in the list of received node classNames to make sure this css rule\n    // applied for root element\n    if (!target) {\n      return classNames.includes(selector.slice(1))\n    }\n\n    // check if selector (className) of specific css rule match target\n    return target instanceof RegExp\n      ? target.test(selector)\n      : minify(selector).includes(minify(target))\n  })\n\nexport const getMediaRules = (rules, media) =>\n  rules\n    .filter((rule) => {\n      const isMediaMatch = rule.media\n        ? rule.media.replace(/\\s/g, '').includes(media.replace(/\\s/g, ''))\n        : false\n      return rule.type === RULE_TYPES.media && isMediaMatch\n    })\n    .reduce((mediaRules, mediaRule) => mediaRules.concat(mediaRule.rules), [])\n\n//\n// Matchers\n/*\n * Taken from\n * https://github.com/facebook/jest/blob/be4bec387d90ac8d6a7596be88bf8e4994bc3ed9/packages/expect/src/jasmine_utils.js#L234\n */\nconst isA = (typeName, value) =>\n  Object.prototype.toString.apply(value) === `[object ${typeName}]`\n\n/*\n * Taken from\n * https://github.com/facebook/jest/blob/be4bec387d90ac8d6a7596be88bf8e4994bc3ed9/packages/expect/src/jasmine_utils.js#L36\n */\nconst isAsymmetric = (obj) => obj && isA('Function', obj.asymmetricMatch)\n\nconst valueMatches = (declaration, value) => {\n  if (value instanceof RegExp) {\n    return value.test(declaration.value)\n  }\n\n  if (isAsymmetric(value)) {\n    return value.asymmetricMatch(declaration.value)\n  }\n\n  return minify(value) === minify(declaration.value)\n}\n\nconst minLeft = /([:;,([{}>~/\\s]|\\/\\*)\\s+/g\nconst minRight = /\\s+([:;,)\\]{}>~/!]|\\*\\/)/g\nconst minify = (s) => s.trim().replace(minLeft, '$1').replace(minRight, '$1')\n\nconst toHaveStyleRule = (received, property, value, options = {}) => {\n  const {target, media} = options\n  const classNames = getClassNamesFromNodes([received])\n  const cssString = getStylesFromClassNames(classNames, getStyleElements())\n  const styles = css.parse(cssString)\n  let preparedRules = styles.stylesheet.rules\n  if (media) {\n    preparedRules = getMediaRules(preparedRules, media)\n  }\n\n  const declaration = preparedRules\n    .filter(\n      (rule) =>\n        rule.type === RULE_TYPES.rule &&\n        hasClassNames(classNames, rule.selectors, target)\n    )\n    .reduce((decs, rule) => decs.concat(rule.declarations), [])\n    .filter(\n      (dec) =>\n        dec.type === 'declaration' && minify(dec.property) === minify(property)\n    )\n    .pop()\n\n  if (!declaration) {\n    return {\n      pass: false,\n      message: () => `Property not found: ${property}`,\n    }\n  }\n\n  const pass = valueMatches(declaration, value)\n\n  const message = () =>\n    `Expected ${property}${pass ? ' not ' : ' '}to match:\\n` +\n    `  ${chalk.green(value)}\\n` +\n    'Received:\\n' +\n    `  ${chalk.red(declaration.value)}`\n\n  return {\n    pass,\n    message,\n  }\n}\n\nexport const matchers = {toHaveStyleRule}\n\n//\n// Pretty serialization\nconst componentSelectorClassNamePattern = /^e[a-zA-Z0-9]+[0-9]+$/\nexport const replaceClassNames = (classNames, styles, code) => {\n  return classNames.reduce((acc, className) => {\n    if (componentSelectorClassNamePattern.test(className)) {\n      return acc\n    }\n    return acc\n  }, `${styles}${styles ? '\\n\\n' : ''}${code}`)\n}\n\nconst getNodes = (node, nodes = []) => {\n  if (Array.isArray(node)) {\n    for (let child of node) {\n      getNodes(child, nodes)\n    }\n    return nodes\n  }\n\n  let children = node.children || (node.props && node.props.children)\n\n  if (children) {\n    // fix for Preact X\n    children = node.props\n      ? Array.isArray(children)\n        ? children\n        : [children]\n      : children\n\n    for (let child of children) {\n      getNodes(child, nodes)\n    }\n  }\n\n  if (typeof node === 'object') {\n    nodes.push(node)\n  }\n\n  return nodes\n}\n\nconst getPrettyStylesFromClassNames = (classNames, elements) => {\n  let styles = getStylesFromClassNames(classNames, elements)\n\n  let prettyStyles\n\n  try {\n    prettyStyles = css.stringify(css.parse(styles))\n  } catch (e) {\n    console.error(e)\n    throw new Error(`There was an error parsing the following css: \"${styles}\"`)\n  }\n\n  return prettyStyles\n}\n\nexport const createSerializer = (opt = {}) => {\n  let {DOMElements = true} = opt\n  let cache = new WeakSet()\n\n  return {\n    test(val) {\n      return (\n        val &&\n        !cache.has(val) &&\n        (isReactElement(val) || (DOMElements && isDOMElement(val)))\n      )\n    },\n\n    print(val, printer) {\n      const nodes = getNodes(val)\n      const classNames = getClassNamesFromNodes(nodes)\n      let elements = getStyleElements()\n      const styles = getPrettyStylesFromClassNames(classNames, elements)\n      nodes.forEach(cache.add, cache)\n      const printedVal = printer(val)\n      nodes.forEach(cache.delete, cache)\n      let keys = getKeys(elements)\n      return replaceClassNames(classNames, styles, printedVal, keys)\n    },\n  }\n}\n\nexport const {print, test} = createSerializer()\nexport default {print, test}\n"],"names":["selectors","node","isReactElement","props","getClassNames","className","class","toString","getClassNamesFromTestRenderer","findWhere","components","dive","type","shouldDive","isTagWithClassName","classes","length","first","prop","getClassNamesFromEnzyme","val","cheerio","isCheerioElement","attr","getClassNamesFromCheerio","getAttribute","getClassNamesFromDOMElement","cssRule","cssText","mediaRules","mediaRule","concat","rules","decs","rule","declarations","acc","componentSelectorClassNamePattern","test","RULE_TYPES","media","split","$$typeof","Symbol","for","hasOwnProperty","err","domElementPattern","isDOMElement","nodeType","constructor","name","getClassNamesFromNodes","nodes","reduce","keyframesPattern","removeCommentPattern","getElementRules","element","nonSpeedyRule","textContent","sheet","slice","call","cssRules","map","getStylesFromClassNames","classNames","elements","arr","iteratee","selectorPattern","RegExp","join","keyframes","styles","forEach","match","undefined","keyframeNameKeys","Object","keys","keyframesStyles","keyframesNamePattern","keyframesNameCache","index","replace","value","getStyleElements","Array","from","document","querySelectorAll","getKeys","unique","filter","Boolean","Set","hasClassNames","target","some","selector","minify","includes","getMediaRules","isMediaMatch","minLeft","minRight","s","trim","matchers","toHaveStyleRule","received","property","options","cssString","preparedRules","css","stylesheet","declaration","dec","pop","pass","message","obj","asymmetricMatch","prototype","apply","isAsymmetric","valueMatches","chalk","green","red","replaceClassNames","code","createSerializer","opt","DOMElements","cache","WeakSet","has","print","printer","getNodes","isArray","child","children","push","prettyStyles","e","console","error","Error","getPrettyStylesFromClassNames","add","printedVal","delete"],"mappings":"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"}