|
1 |
| -const css = require('css') |
2 |
| -const { getCSS, getHashes } = require('./utils') |
| 1 | +const css = require('css'); |
| 2 | +const { getCSS, getHashes } = require('./utils'); |
3 | 3 |
|
4 |
| -const KEY = '__jest-styled-components__' |
| 4 | +const KEY = '__jest-styled-components__'; |
5 | 5 |
|
6 | 6 | const getNodes = (node, nodes = []) => {
|
7 | 7 | if (typeof node === 'object') {
|
8 |
| - nodes.push(node) |
| 8 | + nodes.push(node); |
9 | 9 | }
|
10 | 10 |
|
11 | 11 | if (node.children) {
|
12 |
| - Array.from(node.children).forEach(child => getNodes(child, nodes)) |
| 12 | + Array.from(node.children).forEach(child => getNodes(child, nodes)); |
13 | 13 | }
|
14 | 14 |
|
15 |
| - return nodes |
16 |
| -} |
| 15 | + return nodes; |
| 16 | +}; |
17 | 17 |
|
18 |
| -const markNodes = nodes => nodes.forEach(node => (node[KEY] = true)) |
| 18 | +const markNodes = nodes => nodes.forEach(node => (node[KEY] = true)); |
19 | 19 |
|
20 |
| -const getClassNamesFromDOM = node => Array.from(node.classList) |
| 20 | +const getClassNamesFromDOM = node => Array.from(node.classList); |
21 | 21 | const getClassNamesFromProps = node => {
|
22 |
| - const classNameProp = node.props && (node.props.class || node.props.className) |
| 22 | + const classNameProp = node.props && (node.props.class || node.props.className); |
23 | 23 |
|
24 | 24 | if (classNameProp) {
|
25 |
| - return classNameProp.trim().split(/\s+/) |
| 25 | + return classNameProp.trim().split(/\s+/); |
26 | 26 | }
|
27 | 27 |
|
28 |
| - return [] |
29 |
| -} |
| 28 | + return []; |
| 29 | +}; |
30 | 30 |
|
31 | 31 | const getClassNames = nodes =>
|
32 | 32 | nodes.reduce((classNames, node) => {
|
33 |
| - let newClassNames = null |
| 33 | + let newClassNames = null; |
34 | 34 |
|
35 | 35 | if (global.Element && node instanceof global.Element) {
|
36 |
| - newClassNames = getClassNamesFromDOM(node) |
| 36 | + newClassNames = getClassNamesFromDOM(node); |
37 | 37 | } else {
|
38 |
| - newClassNames = getClassNamesFromProps(node) |
| 38 | + newClassNames = getClassNamesFromProps(node); |
39 | 39 | }
|
40 | 40 |
|
41 |
| - newClassNames.forEach(className => classNames.add(className)) |
| 41 | + newClassNames.forEach(className => classNames.add(className)); |
42 | 42 |
|
43 |
| - return classNames |
44 |
| - }, new Set()) |
| 43 | + return classNames; |
| 44 | + }, new Set()); |
45 | 45 |
|
46 |
| -const filterClassNames = (classNames, hashes) => |
47 |
| - classNames.filter(className => hashes.includes(className)) |
| 46 | +const filterClassNames = (classNames, hashes) => classNames.filter(className => hashes.includes(className)); |
48 | 47 |
|
49 | 48 | const includesClassNames = (classNames, selectors) =>
|
50 |
| - classNames.some(className => |
51 |
| - selectors.some(selector => selector.includes(className)) |
52 |
| - ) |
| 49 | + classNames.some(className => selectors.some(selector => selector.includes(className))); |
53 | 50 |
|
54 | 51 | const filterRules = classNames => rule =>
|
55 |
| - rule.type === 'rule' && |
56 |
| - includesClassNames(classNames, rule.selectors) && |
57 |
| - rule.declarations.length |
| 52 | + rule.type === 'rule' && includesClassNames(classNames, rule.selectors) && rule.declarations.length; |
58 | 53 |
|
59 | 54 | const getAtRules = (ast, filter) =>
|
60 | 55 | ast.stylesheet.rules
|
61 | 56 | .filter(rule => rule.type === 'media' || rule.type === 'supports')
|
62 | 57 | .reduce((acc, atRule) => {
|
63 |
| - atRule.rules = atRule.rules.filter(filter) |
| 58 | + atRule.rules = atRule.rules.filter(filter); |
64 | 59 |
|
65 |
| - if (atRule.rules.length) { |
66 |
| - return acc.concat(atRule) |
67 |
| - } |
68 |
| - |
69 |
| - return acc |
70 |
| - }, []) |
| 60 | + return acc.concat(atRule); |
| 61 | + }, []); |
71 | 62 |
|
72 | 63 | const getStyle = classNames => {
|
73 |
| - const ast = getCSS() |
74 |
| - const filter = filterRules(classNames) |
75 |
| - const rules = ast.stylesheet.rules.filter(filter) |
76 |
| - const atRules = getAtRules(ast, filter) |
| 64 | + const ast = getCSS(); |
| 65 | + const filter = filterRules(classNames); |
| 66 | + const rules = ast.stylesheet.rules.filter(filter); |
| 67 | + const atRules = getAtRules(ast, filter); |
77 | 68 |
|
78 |
| - ast.stylesheet.rules = rules.concat(atRules) |
| 69 | + ast.stylesheet.rules = rules.concat(atRules); |
79 | 70 |
|
80 |
| - return css.stringify(ast) |
81 |
| -} |
| 71 | + return css.stringify(ast); |
| 72 | +}; |
82 | 73 |
|
83 | 74 | const getClassNamesFromSelectorsByHashes = (classNames, hashes) => {
|
84 |
| - const ast = getCSS() |
85 |
| - const filter = filterRules(classNames) |
86 |
| - const rules = ast.stylesheet.rules.filter(filter) |
| 75 | + const ast = getCSS(); |
| 76 | + const filter = filterRules(classNames); |
| 77 | + const rules = ast.stylesheet.rules.filter(filter); |
87 | 78 |
|
88 |
| - const selectors = rules.map(rule => rule.selectors) |
89 |
| - const classNamesIncludingFromSelectors = new Set(classNames) |
| 79 | + const selectors = rules.map(rule => rule.selectors); |
| 80 | + const classNamesIncludingFromSelectors = new Set(classNames); |
90 | 81 | const addHashFromSelectorListToClassNames = hash =>
|
91 |
| - selectors.forEach( |
92 |
| - selectorList => |
93 |
| - selectorList[0].includes(hash) && |
94 |
| - classNamesIncludingFromSelectors.add(hash) |
95 |
| - ) |
| 82 | + selectors.forEach(selectorList => selectorList[0].includes(hash) && classNamesIncludingFromSelectors.add(hash)); |
96 | 83 |
|
97 |
| - hashes.forEach(addHashFromSelectorListToClassNames) |
| 84 | + hashes.forEach(addHashFromSelectorListToClassNames); |
98 | 85 |
|
99 |
| - return [...classNamesIncludingFromSelectors] |
100 |
| -} |
| 86 | + return [...classNamesIncludingFromSelectors]; |
| 87 | +}; |
101 | 88 |
|
102 | 89 | const replaceClassNames = (result, classNames, style) =>
|
103 | 90 | classNames
|
104 | 91 | .filter(className => style.includes(className))
|
105 |
| - .reduce( |
106 |
| - (acc, className, index) => |
107 |
| - acc.replace(new RegExp(className, 'g'), `c${index++}`), |
108 |
| - result |
109 |
| - ) |
| 92 | + .reduce((acc, className, index) => acc.replace(new RegExp(className, 'g'), `c${index++}`), result); |
110 | 93 |
|
111 | 94 | const replaceHashes = (result, hashes) =>
|
112 | 95 | hashes.reduce(
|
113 |
| - (acc, className) => |
114 |
| - acc.replace( |
115 |
| - new RegExp(`((class|className)="[^"]*?)${className}\\s?([^"]*")`, 'g'), |
116 |
| - '$1$3' |
117 |
| - ), |
| 96 | + (acc, className) => acc.replace(new RegExp(`((class|className)="[^"]*?)${className}\\s?([^"]*")`, 'g'), '$1$3'), |
118 | 97 | result
|
119 |
| - ) |
| 98 | + ); |
120 | 99 |
|
121 |
| -const styleSheetSerializer = { |
| 100 | +module.exports = { |
122 | 101 | test(val) {
|
123 | 102 | return (
|
124 | 103 | val &&
|
125 | 104 | !val[KEY] &&
|
126 |
| - (val.$$typeof === Symbol.for('react.test.json') || |
127 |
| - (global.Element && val instanceof global.Element)) |
128 |
| - ) |
| 105 | + (val.$$typeof === Symbol.for('react.test.json') || (global.Element && val instanceof global.Element)) |
| 106 | + ); |
129 | 107 | },
|
130 | 108 |
|
131 | 109 | print(val, print) {
|
132 |
| - const nodes = getNodes(val) |
133 |
| - markNodes(nodes) |
| 110 | + const nodes = getNodes(val); |
| 111 | + markNodes(nodes); |
134 | 112 |
|
135 |
| - const hashes = getHashes() |
136 |
| - let classNames = [...getClassNames(nodes)] |
137 |
| - classNames = filterClassNames(classNames, hashes) |
| 113 | + const hashes = getHashes(); |
138 | 114 |
|
139 |
| - const style = getStyle(classNames) |
140 |
| - const classNamesToReplace = getClassNamesFromSelectorsByHashes( |
141 |
| - classNames, |
142 |
| - hashes |
143 |
| - ) |
144 |
| - const code = print(val) |
| 115 | + let classNames = [...getClassNames(nodes)]; |
| 116 | + classNames = filterClassNames(classNames, hashes); |
145 | 117 |
|
146 |
| - let result = `${style}${style ? '\n\n' : ''}${code}` |
147 |
| - result = replaceClassNames(result, classNamesToReplace, style) |
148 |
| - result = replaceHashes(result, hashes) |
| 118 | + const style = getStyle(classNames); |
| 119 | + const classNamesToReplace = getClassNamesFromSelectorsByHashes(classNames, hashes); |
| 120 | + const code = print(val); |
149 | 121 |
|
150 |
| - return result |
151 |
| - }, |
152 |
| -} |
| 122 | + let result = `${style}${style ? '\n\n' : ''}${code}`; |
| 123 | + result = replaceClassNames(result, classNamesToReplace, style); |
| 124 | + result = replaceHashes(result, hashes); |
153 | 125 |
|
154 |
| -module.exports = styleSheetSerializer |
| 126 | + return result; |
| 127 | + }, |
| 128 | +}; |
0 commit comments